为什么列表(list)没有像字典(dictionary)一样安全的“get”方法?
>>> 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
为什么列表(list)没有像字典(dictionary)一样安全的“get”方法?
>>> 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
最终,.get
方法可能没有安全性,因为dict
是一种关联集合(值与名称相关联),在不抛出异常的情况下检查键是否存在并返回其值是低效的,而访问列表元素时避免异常非常简单(因为len
方法非常快)。 .get
方法允许您查询与名称相关联的值,而不是直接访问字典中的第37个项目(这更像是要求列表的操作)。
当然,您可以轻松地自己实现:
def safe_list_get (l, idx, default):
try:
return l[idx]
except IndexError:
return default
您甚至可以将其猴子补丁到__builtins__.list
构造函数中的__main__
,但这将是一种不太普遍的更改,因为大多数代码不使用它。如果您只想在自己编写的列表中使用它,可以简单地继承list
并添加get
方法。
list
。 - Imran.get
解决了列表所没有的问题——在获取可能不存在的数据时,避免异常的高效方式。确定有效的列表索引非常简单且高效,但是对于字典中的键值,没有特别好的方法来做到这一点。 - Nick BastinO(1)
。从复杂度的角度来看,它们并不像检查len
那样快,但在复杂度上它们都是O(1)
。正确答案取决于典型的用法和语义... - Mark Longairdict
仅在最理想情况下为O(1),并非所有情况都是如此。 - Nick Bastin.get()
方法,要么是代码(或环境)其他方面存在问题。使用这种方法的关键在于提高代码的可读性。使用“传统”技术需要在每个需要这样做的地方编写四行代码。而.get()
技术只需要一行,并且可以轻松地与随后的方法调用链接起来(例如:my_list.get(2, '').uppercase()
)。 - Tyler Crompton如果您想要获取第一个元素,可以使用此方法,例如my_list.get(0)
>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'
我知道这不完全是你所要求的,但它可能有助于其他人。
next(iter(my_list[index:index+1]), 'fail')
允许任何索引,而不仅仅是0。或者更少的FP但可以说更Pythonic,并且几乎肯定更可读:my_list[index] if index < len(my_list) else 'fail'
。 - alphabetasoupn
个元素,那么你可以使用next(iter(my_list[n:n+1]), 'fail')
。 - Stef可能是因为这对于列表语义并没有太多意义。但是,您可以通过子类化轻松创建自己的列表。
class safelist(list):
def get(self, index, default=None):
try:
return self.__getitem__(index)
except IndexError:
return default
def _test():
l = safelist(range(10))
print l.get(20, "oops")
if __name__ == "__main__":
_test()
return self[index]
? - timgeb不需要使用`get()`方法,对于列表来说这样使用是可以的。这只是用法上的区别。
>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'
.get
方法(不过我不确定在这种情况下如何解释索引的含义,或者为什么它会失败)。 - Nick Bastinlst[i] if -len(lst) <= i < len(l) else 'fail'
。 - micCredits to jose.angel.jimenez and Gus Bus.
对于“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', 'b', 'c']
f = lambda l, x, d: l[x:x+1] and l[x] or d
print(f(liste, 0, 'default')) # returns a
print(f(liste, 1, 'default')) # returns b
print(f(liste, 2, 'default')) # returns c
print(f(liste, 3, 'default')) # returns default
使用 Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)
进行测试
一个合理的做法是将列表转换为字典,然后使用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')
dict(enumerate(my_list))
代替zip range len
的方法。 - Marian试试这个:
>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'
next(iter(a[i:i+1]), 'fail')
比next(iter(a[i:]), 'fail')
更有效率。 - Stef所以我对此进行了更多的研究,结果发现没有特定的方法来解决这个问题。当我发现list.index(value)时感到兴奋,它返回指定项的索引,但没有找到获取特定索引值的方法。如果您不想使用safe_list_get解决方案,以下是一些单行if语句,根据情况可以帮助您完成任务:
>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'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
还没有进行基准测试来确定哪个更快。
dict.get()
的方法来返回默认值,而是必须捕获IndexError
异常?”因此,这确实是关于语言/库特性(而不是OOP vs. FP上下文)。此外,你可能需要说明一下你对“pythonic”的使用,也许是WWGD(因为他对FP Python的鄙视是众所周知的),而不仅仅是满足PEP8/20。 - cowbertlen(x) > 4
吗?如果 len(x) == 4
,那么 x[4]
就越界了。 - mic字典用于查找。询问条目是否存在是有意义的。列表通常被迭代。不常询问L[10]是否存在,而是询问L的长度是否为11。
如果您:
您可以使用以下代码:
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)
''
list_get([""], 0)
失败应该返回 ""
,但实际上会返回 0
。 - Marek R
l[10:11]
来获取列表中的元素,而不是使用索引方式l[10]
,即使要获取的元素不存在,也不会出现IndexError错误,而是会得到一个空的子列表。(如果元素存在,则该子列表将包含所需元素。) - jsbueno.get
的想法。它相当于l[i] if i < len(l) else default
,但更易读、更简洁,并允许i
是一个表达式,而不必重新计算它。 - Paul Drapermylist.get(myindex, mydefault)
被拒绝了,转而采用(mylist[myindex:myindex+1] or mydefault)[0]
:-/ - Rotareti