Using nested generator expression in Python 2.7
google-app-engine, python
Solution
Just change the order of evaluation
props = set([k for k in u.properties().keys() for u in users])
to
props = set([k for u in users for k in u.properties().keys() ])
also you don't need a list comprehension but generator expression with a set comprehension would work here
props = set(k for u in users for k in u.properties().keys() )
Order of evaluation is from right to left
In your original expression
set([k for k in u.properties().keys() for u in users])
can be broken as
for k in u.properties().keys(): # Here u is undefined
for u in users:
#what ever
The interesting phenomena of using a Dummy expression is the fact that List Comprehension Leaks Variables, which causes `u` to be leaked in the global scope
So
[u.properties().keys() for u in users]
leaks `u` in global scope,
which makes
set([k for k in u.properties().keys() for u in users])
legitimate
The following example shows, how list comprehension leaks variables
>>> 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]
>>>
Problem
In an appengine application, I want to build a set of all property names for a list of objects. This should be fairly straightforward: ``` users = security.User.all().fetch(1000) props = set([k for k in u.properties().keys() for u in users]) ``` However, the code above results in an error: ``` 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 ``` After some experiments in the debugger I've noticed that adding a dummy expression fixes the code: ``` 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]) ``` This is quite counter-intuitive to me, why is original version failing in Python 2.7? and why adding a 'useless' expression in the middle fixes the problem?