在Python 2.7中使用嵌套生成器表达式
在appengine应用程序中,我想为对象列表构建一组所有属性名。 这应该相当简单:在Python 2.7中使用嵌套生成器表达式,python,google-app-engine,Python,Google App Engine,在appengine应用程序中,我想为对象列表构建一组所有属性名。 这应该相当简单: users = security.User.all().fetch(1000) props = set([k for k in u.properties().keys() for u in users]) 但是,上面的代码会导致错误: File "/Users/paulkorzhyk/Projects/appengine-flask-template/app/app.py", line 70, in allu
users = security.User.all().fetch(1000)
props = set([k for k in u.properties().keys() for u in users])
但是,上面的代码会导致错误:
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
在调试器中进行了一些实验后,我注意到添加虚拟表达式可以修复代码:
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])
这与我的直觉相反,为什么原始版本在Python2.7中失败了?为什么在中间添加一个“无用的”表达式来解决这个问题? < P>只是改变评价顺序
props = set([k for k in u.properties().keys() for u in users])
到
另外,您不需要列表理解,但是具有集合理解的生成器表达式在这里也可以工作
props = set(k for u in users for k in u.properties().keys() )
评估的顺序是从右到左
用你原来的表情
set([k for k in u.properties().keys() for u in users])
可以破译为
for k in u.properties().keys(): # Here u is undefined
for u in users:
#what ever
使用伪表达式的有趣现象是列表理解泄漏变量,这导致u
在全局范围内泄漏
所以
全球范围内的泄漏u
这使得
set([k for k in u.properties().keys() for u in users])
合法的
下面的示例显示如何列出变量
>>> 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]
>>>
>>deli
>>>foo=[范围(1,10)表示范围(10)]
>>>globals()['i']
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
globals()['i']
KeyError:“我很高兴。”
>>>[我代表我在福]
[[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]
>>>
原始示例失败的原因是您的for
子句顺序错误。列表/生成器理解中的for
子句的顺序与将代码写成嵌套for循环时的顺序相同。也就是说,最左边的是最外面的,最右边的是最里面的。切换for
子句的顺序以使其工作
伪表达式更改行为的原因是伪表达式是列表理解,在Python 2中,列表理解(与生成器理解不同)将其循环变量泄漏到封闭范围。泄漏的
u
允许第二个示例运行,但它没有按照您认为的那样运行,因为props=…
行中的for
子句的顺序仍然错误。它只在u
的一个值上循环,即来自虚拟表达式的最后一个u
值。根据这个答案,关联应该是从左到右的,因此循环语句应该重新排序。感谢您的解释,真的很有帮助。变量泄漏是一个bug吗?这不是bug,而是Python 2.3之后的一个特性。此功能已从Python 3.0中删除。参考
set([k for k in u.properties().keys() for u in users])
>>> 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]
>>>