生成器表达式Python

Apu*_*lol 16 python dictionary generator generator-expression

我有一个字典列表,如下所示:

lst = [{'a': 5}, {'b': 6}, {'c': 7}, {'d': 8}]
Run Code Online (Sandbox Code Playgroud)

我写了一个生成器表达式,如:

next((itm for itm in lst if itm['a']==5))
Run Code Online (Sandbox Code Playgroud)

现在奇怪的是,虽然这适用于它的键值对,'a' 但下次会为所有其他表达式抛出错误.表达:

next((itm for itm in lst if itm['b']==6))
Run Code Online (Sandbox Code Playgroud)

错误:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
KeyError: 'b'
Run Code Online (Sandbox Code Playgroud)

Wil*_*sem 33

这并不奇怪.对于每一itm个人lst.它将首先评估过滤条款.现在,如果是filter子句itm['b'] == 6,它将尝试'b'从该字典中获取密钥.但由于第一个字典没有这样的密钥,它会引发错误.

对于第一个过滤器示例,这不是问题,因为第一个字典一个'a'键.的next(..)是仅在感兴趣的第一由发电机发射的元件.所以它永远不会要求过滤更多的元素.

您可以.get(..)在此处使查找更加安全:

next((itm for itm in lst if itm.get('b',None)==6))
Run Code Online (Sandbox Code Playgroud)

如果字典没有这样的键,则该.get(..)部分将返回None.并且由于None不等于6,因此过滤器将省略第一个字典并进一步查看另一个匹配.请注意,如果未指定默认值,None则为默认值,因此等效语句为:

next((itm for itm in lst if itm.get('b')==6))
Run Code Online (Sandbox Code Playgroud)

我们也可以省略生成器的括号:只有当有多个参数时,我们才需要这些附加的括号:

next(itm for itm in lst if itm.get('b')==6)
Run Code Online (Sandbox Code Playgroud)

  • 也许只是`itm.get('b')== 6`(`无'是默认值) (3认同)
  • @ApurvaKunkulol:因为第一个导致错误.如果代码引发错误,则执行流程中止,并且调用堆栈*展开*直到有一个处理错误的捕获机制.在`d.get('x')`的情况下,没有这样的错误.因为如果缺少密钥,则返回"None".因此,这将使正常的代码路径继续,这将获取下一个`itm`并检查该`itm`上的过滤器. (3认同)

pok*_*oke 15

分别看看你的生成器表达式:

(itm for itm in lst if itm['a']==5)
Run Code Online (Sandbox Code Playgroud)

这将收集列表中的所有项目itm['a'] == 5.到现在为止还挺好.

当你调用next()它时,你告诉Python 从该生成器表达式生成第一个项目.但只有第一个.

因此,当您有条件时itm['a'] == 5,生成器将获取列表的第一个元素,{'a': 5}并对其执行检查.条件为true,因此该项由生成器表达式生成并返回next().

现在,当您将条件更改为时itm['b'] == 6,生成器将再次获取列表的第一个元素{'a': 5},并尝试使用键获取元素b.这将失败:

>>> itm = {'a': 5}
>>> itm['b']
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    itm['b']
KeyError: 'b'
Run Code Online (Sandbox Code Playgroud)

它甚至没有机会查看第二个元素,因为它在尝试查看第一个元素时已经失败了.

要解决此问题,您必须避免使用可以在KeyError此处引发的表达式.您可以使用dict.get()尝试检索值而不引发异常:

>>> lst = [{'a': 5}, {'b': 6}, {'c': 7}, {'d': 8}]
>>> next((itm for itm in lst if itm.get('b') == 6))
{'b': 6}
Run Code Online (Sandbox Code Playgroud)


fre*_*ish 6

如果词典中没有键,显然itm['b']会提出一个.一种方法是做KeyError'b'

next((itm for itm in lst if 'b' in itm and itm['b']==6))
Run Code Online (Sandbox Code Playgroud)

如果你不想None在任何词典中,那么你可以简化它

next((itm for itm in lst if itm.get('b')==6))
Run Code Online (Sandbox Code Playgroud)

(这与你比较时的工作方式相同6,但是如果要进行比较会产生错误的结果None)

或安全地使用占位符

PLACEHOLDER = object()
next((itm for itm in lst if itm.get('b', PLACEHOLDER)==6))
Run Code Online (Sandbox Code Playgroud)