在Python 2.7中使用嵌套的生成器表达式

Pau*_*aul 5 python google-app-engine

在appengine应用程序中,我想为对象列表构建一组所有属性名称.这应该是相当简单的:

users = security.User.all().fetch(1000)
props = set([k for k in u.properties().keys() for u in users])
Run Code Online (Sandbox Code Playgroud)

但是,上面的代码会导致错误:

File "/Users/paulkorzhyk/Projects/appengine-flask-template/app/app.py", line 70, in allusers
props = set([k for k in u.properties().keys() for u in users])
UnboundLocalError: local variable 'u' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

在调试器中进行了一些实验后,我注意到添加虚拟表达式修复了代码:

users = security.User.all().fetch(1000)
[u.properties().keys() for u in users]
props = set([k for k in u.properties().keys() for u in users])
Run Code Online (Sandbox Code Playgroud)

这对我来说非常违反直觉,为什么原始版本在Python 2.7中失败?为什么在中间添加一个"无用的"表达式来修复问题?

Abh*_*jit 7

只需更改评估顺序即可

props = set([k for k in u.properties().keys() for u in users])
Run Code Online (Sandbox Code Playgroud)

props = set([k for u in users for k in u.properties().keys() ])
Run Code Online (Sandbox Code Playgroud)

你也不需要列表理解,但是具有集合理解的生成器表达式可以在这里工作

props = set(k for u in users for k in u.properties().keys() )
Run Code Online (Sandbox Code Playgroud)

评估顺序是从右到左

在你的原始表达中

set([k for k in u.properties().keys() for u in users])
Run Code Online (Sandbox Code Playgroud)

可以打破

for k in u.properties().keys(): # Here u is undefined
    for u in users:
        #what ever
Run Code Online (Sandbox Code Playgroud)

使用Dummy表达式的有趣现象是List Comprehension Leaks Variables导致u在全局范围内泄露的事实

所以

[u.properties().keys() for u in users]
Run Code Online (Sandbox Code Playgroud)

泄漏u在全球范围内,

这使得

set([k for k in u.properties().keys() for u in users])
Run Code Online (Sandbox Code Playgroud)

合法

以下示例显示了列表推导如何泄漏变量

>>> del i
>>> foo = [range(1,10) for _ in range(10)]
>>> globals()['i']

Traceback (most recent call last):
  File "<pyshell#84>", line 1, in <module>
    globals()['i']
KeyError: 'i'
>>> [i for i in foo]
[[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9]]
>>> globals()['i']
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> 
Run Code Online (Sandbox Code Playgroud)