为什么列表没有安全的“获取”像字典一样的方法?

发布于 2024-10-19 11:11:40 字数 256 浏览 9 评论 0原文

为什么列表没有像字典那样安全的“获取”方法?

>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'

>>> l = [1]
>>> l[10]
IndexError: list index out of range

Why doesn't list have a safe "get" method like dictionary?

>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'

>>> l = [1]
>>> l[10]
IndexError: list index out of range

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

萌︼了一个春 2024-10-26 11:11:40

最终它可能没有安全的 .get 方法,因为 dict 是一个关联集合(值与名称关联),检查键是否存在是低效的。存在(并返回其值)而不引发异常,而避免访问列表元素的异常非常简单(因为 len 方法非常快)。 .get 方法允许您查询与名称关联的值,而不是直接访问字典中的第 37 项(这更像是您对列表的要求)。

当然,您可以轻松地自己实现:

def safe_list_get (l, idx, default):
  try:
    return l[idx]
  except IndexError:
    return default

您甚至可以将其猴子补丁到 __main__ 中的 __builtins__.list 构造函数上,但这将是一个不太普遍的更改,因为大多数代码都不会不要使用它。如果您只想将其与您自己的代码创建的列表一起使用,您可以简单地子类 list 并添加 get 方法。

Ultimately it probably doesn't have a safe .get method because a dict is an associative collection (values are associated with names) where it is inefficient to check if a key is present (and return its value) without throwing an exception, while it is super trivial to avoid exceptions accessing list elements (as the len method is very fast). The .get method allows you to query the value associated with a name, not directly access the 37th item in the dictionary (which would be more like what you're asking of your list).

Of course, you can easily implement this yourself:

def safe_list_get (l, idx, default):
  try:
    return l[idx]
  except IndexError:
    return default

You could even monkeypatch it onto the __builtins__.list constructor in __main__, but that would be a less pervasive change since most code doesn't use it. If you just wanted to use this with lists created by your own code you could simply subclass list and add the get method.

离线来电— 2024-10-26 11:11:40

如果您想要第一个元素,例如 my_list.get(0)

>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'

我知道这并不完全是您所要求的,但它可能对其他人有帮助。

This works if you want the first element, like my_list.get(0)

>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'

I know it's not exactly what you asked for but it might help others.

故笙诉离歌 2024-10-26 11:11:40

可能是因为它对于列表语义来说没有多大意义。但是,您可以通过子类化轻松创建自己的。

class safelist(list):
    def get(self, index, default=None):
        try:
            return self[index]
        except IndexError:
            return default

def _test():
    l = safelist(range(10))
    print l.get(20, "oops")

if __name__ == "__main__":
    _test()

Probably because it just didn't make much sense for list semantics. However, you can easily create your own by subclassing.

class safelist(list):
    def get(self, index, default=None):
        try:
            return self[index]
        except IndexError:
            return default

def _test():
    l = safelist(range(10))
    print l.get(20, "oops")

if __name__ == "__main__":
    _test()
池予 2024-10-26 11:11:40

对于列表来说,像这样使用而不是使用 .get 应该没问题。只是用法不同而已。

>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'

Instead of using .get, using like this should be ok for lists. Just a usage difference.

>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'
靖瑶 2024-10-26 11:11:40

致谢 jose.angel.jimenezGus BusMarek R


对于“oneliner”粉丝......


如果您想要列表的第一个元素,或者如果列表为空时您想要默认值,请尝试:

liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)

返回 a

liste = []
value = (liste[0:1] or ('default',))[0]
print(value)

返回 default


其他元素的示例...

liste = ['a', 'b', 'c']
print(liste[0:1])  # returns ['a']
print(liste[1:2])  # returns ['b']
print(liste[2:3])  # returns ['c']
print(liste[3:4])  # returns []

使用默认后备…

liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0])  # returns a
print((liste[1:2] or ('default',))[0])  # returns b
print((liste[2:3] or ('default',))[0])  # returns c
print((liste[3:4] or ('default',))[0])  # returns default

可能更短:

liste = ['a', 'b', 'c']
value, = liste[:1] or ('default',)
print(value)  # returns a

看起来你需要等号前面的逗号,等号和后面的括号。


更通用:

liste = ['a', None, 'c']
f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) else d
print(f(liste, 0))   # returns a
print(f(liste, 1))   # returns None
print(f(liste, 2))   # returns c
print(f(liste, 3))   # returns default
print(f(liste, -1))  # returns c

更通用的虚假管理:

liste = ['a', None, 'c']
f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) and l[x] not in (None, "", 0, False, [], {}, (), set(), frozenset(), b'', bytearray(b'')) else d
print(f(liste, 0))   # returns a
print(f(liste, 1))   # returns default
print(f(liste, 2))   # returns c
print(f(liste, 3))   # returns default
print(f(liste, -1))  # returns c

使用 Python 3.6.0 进行测试(v3.6.0:41df79263a11,2016 年 12 月 22 日,17:23:13)

Credits to jose.angel.jimenez, Gus Bus and Marek R


For the "oneliner" fans…


If you want the first element of a list or if you want a default value if the list is empty try:

liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)

returns a

and

liste = []
value = (liste[0:1] or ('default',))[0]
print(value)

returns default


Examples for other elements…

liste = ['a', 'b', 'c']
print(liste[0:1])  # returns ['a']
print(liste[1:2])  # returns ['b']
print(liste[2:3])  # returns ['c']
print(liste[3:4])  # returns []

With default fallback…

liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0])  # returns a
print((liste[1:2] or ('default',))[0])  # returns b
print((liste[2:3] or ('default',))[0])  # returns c
print((liste[3:4] or ('default',))[0])  # returns default

Possibly shorter:

liste = ['a', 'b', 'c']
value, = liste[:1] or ('default',)
print(value)  # returns a

It looks like you need the comma before the equal sign, the equal sign and the latter parenthesis.


More general:

liste = ['a', None, 'c']
f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) else d
print(f(liste, 0))   # returns a
print(f(liste, 1))   # returns None
print(f(liste, 2))   # returns c
print(f(liste, 3))   # returns default
print(f(liste, -1))  # returns c

More general with falsy management:

liste = ['a', None, 'c']
f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) and l[x] not in (None, "", 0, False, [], {}, (), set(), frozenset(), b'', bytearray(b'')) else d
print(f(liste, 0))   # returns a
print(f(liste, 1))   # returns default
print(f(liste, 2))   # returns c
print(f(liste, 3))   # returns default
print(f(liste, -1))  # returns c

Tested with Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)

戏剧牡丹亭 2024-10-26 11:11:40

您可以做的合理的事情是将列表转换为字典,然后使用 get 方法访问它:

>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')

A reasonable thing you can do is to convert the list into a dict and then access it with the get method:

>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')
孤独难免 2024-10-26 11:11:40

试试这个:

>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'

Try this:

>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'
哆啦不做梦 2024-10-26 11:11:40

所以我对此做了一些更多的研究,结果发现没有任何具体的内容。当我发现 list.index(value) 时,我很兴奋,它返回指定项目的索引,但没有任何东西可以获取特定索引处的值。因此,如果您不想使用我认为非常好的 safe_list_get 解决方案。以下是一些 1 行 if 语句,可以根据情况为您完成工作:

>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'No'

您还可以使用 None 而不是 'No',这更有意义。:

>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None

另外,如果您只想获取其中的第一项或最后一项列表,这有效

end_el = x[-1] if x else None

您也可以将它们放入函数中,但我仍然喜欢 IndexError 异常解决方案。我尝试了 safe_list_get 解决方案的虚拟版本,并使其变得更简单(无默认值):

def list_get(l, i):
    try:
        return l[i]
    except IndexError:
        return None

尚未进行基准测试来了解最快的。

So I did some more research into this and it turns out there isn't anything specific for this. I got excited when I found list.index(value), it returns the index of a specified item, but there isn't anything for getting the value at a specific index. So if you don't want to use the safe_list_get solution which I think is pretty good. Here are some 1 liner if statements that can get the job done for you depending on the scenario:

>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'No'

You can also use None instead of 'No', which makes more sense.:

>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None

Also if you want to just get the first or last item in the list, this works

end_el = x[-1] if x else None

You can also make these into functions but I still liked the IndexError exception solution. I experimented with a dummied down version of the safe_list_get solution and made it a bit simpler (no default):

def list_get(l, i):
    try:
        return l[i]
    except IndexError:
        return None

Haven't benchmarked to see what is fastest.

难以启齿的温柔 2024-10-26 11:11:40

字典是用来查找的。询问条目是否存在是有意义的。列表通常是迭代的。询问 L[10] 是否存在并不常见,而是询问 L 的长度是否为 11。

Dictionaries are for look ups. It makes sense to ask if an entry exists or not. Lists are usually iterated. It isn't common to ask if L[10] exists but rather if the length of L is 11.

っ〆星空下的拥抱 2024-10-26 11:11:40

如果你

  1. 想要一个单行,
  2. 不希望在你不需要的快乐代码路径中使用 try / except ,并且
  3. 希望默认值是可选的,

你可以使用这个:

list_get = lambda l, x, d=None: d if not l[x:x+1] else l[x]

用法如下:

>>> list_get(['foo'], 4) == None
True
>>> list_get(['hootenanny'], 4, 'ho down!')
'ho down!'
>>> list_get([''], 0)
''

If you

  1. want a one liner,
  2. prefer not having try / except in your happy code path where you needn't, and
  3. want the default value to be optional,

you can use this:

list_get = lambda l, x, d=None: d if not l[x:x+1] else l[x]

Usage looks like:

>>> list_get(['foo'], 4) == None
True
>>> list_get(['hootenanny'], 4, 'ho down!')
'ho down!'
>>> list_get([''], 0)
''
残龙傲雪 2024-10-26 11:11:40

这不是一个极其通用的解决方案,但我遇到过这样的情况:我期望长度为 3 到 5 的列表(带有保护 if),并且我将值分解为命名变量。我发现了一种简单而简洁的方法:

foo = (argv + [None, None])[3]
bar = (argv + [None, None])[4]

现在 foobar 要么是列表中的第四个和第五个值,要么是 None 如果没有那么多的价值。

This isn't an extremely general-purpose solution, but I had a case where I expected a list of length 3 to 5 (with a guarding if), and I was breaking out the values to named variables. A simple and concise way I found for this involved:

foo = (argv + [None, None])[3]
bar = (argv + [None, None])[4]

Now foo and bar are either the 4th and 5th values in the list, or None if there weren't that many values.

丶情人眼里出诗心の 2024-10-26 11:11:40

对于较小的索引值,您可以将

my_list.get(index, default)

实现为

(my_list + [default] * (index + 1))[index]

如果您知道提前索引是什么,那么这可以简化,例如,如果您知道它是 1 那么您可以执行

(my_list + [default, default])[index]

因为列表是前向打包的,这是唯一的失败情况我们需要担心的是超出了列表的末尾。这种方法用足够的默认值填充列表的末尾,以保证索引被覆盖。

For small index values you can implement

my_list.get(index, default)

as

(my_list + [default] * (index + 1))[index]

If you know in advance what index is then this can be simplified, for example if you knew it was 1 then you could do

(my_list + [default, default])[index]

Because lists are forward packed the only fail case we need to worry about is running off the end of the list. This approach pads the end of the list with enough defaults to guarantee that index is covered.

煮茶煮酒煮时光 2024-10-26 11:11:40

您的用例基本上仅与处理固定长度的数组和矩阵时相关,以便您事先知道它们有多长。在这种情况下,您通常还会在手动用 None 或 0 填充它们之前创建它们,因此实际上您将使用的任何索引都已经存在。

你可以这样说:我经常需要字典上的 .get() 。作为一名全职程序员十年之后,我认为我不再需要将它列入清单。 :)

Your usecase is basically only relevant for when doing arrays and matrixes of a fixed length, so that you know how long they are before hand. In that case you typically also create them before hand filling them up with None or 0, so that in fact any index you will use already exists.

You could say this: I need .get() on dictionaries quite often. After ten years as a full time programmer I don't think I have ever needed it on a list. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文