Issue 31126: dict comprehension shouldn't raise UnboundLocalError (original) (raw)
Created on 2017-08-06 13:17 by ksqsf, last changed 2022-04-11 14:58 by admin. This issue is now closed.
Messages (5)
Author: ksqsf (ksqsf)
Date: 2017-08-06 13:17
The code key = ["a", "b"] val = [1, 2] dic = {key:val for key in key for val in val} will raise UnboundLocalError in Python 3.6.2 and 2.7.13.
Intuitively, the element 'key' and the list 'key' are not the same, so generally the expected result is {"a": 1, "b": 2}.
There are similar cases for listcomps, setcomps and genexprs: l = [1, 2, 3] {l for l in l} # => {1, 2, 3} [l for l in l] # => [1, 2, 3] for l in (l for l in l): print(l, end=' ') # => 1 2 3 All of them do as what is expected.
For consistency and intuitiveness, the behavior of distcomps should be modified so that no UnboundLocalError is raised.
Author: R. David Murray (r.david.murray) *
Date: 2017-08-06 14:07
The behavior is consistent:
a = [1, 2] b = [3, 4] [(a, b) for a in a for b in b] Traceback (most recent call last): File "", line 1, in File "", line 1, in UnboundLocalError: local variable 'b' referenced before assignment
I'm not sure why it is only the nested loop that raises the error (https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries seems to imply it should raise for both)
By the way, the actual result of your comprehesion would be {"a": 2, "b" 2}.
Author: Eryk Sun (eryksun) *
Date: 2017-08-06 14:26
Comprehensions evaluate the iterator for the outermost loop in the surrounding scope. The iterators for all inner loops are evaluated in the local scope of the comprehension itself.
Author: R. David Murray (r.david.murray) *
Date: 2017-08-06 18:05
I wonder if that explanation should be added to the doc section to which I pointed. I thought I'd remembered something like that being in there, but it isn't.
Author: Eryk Sun (eryksun) *
Date: 2017-08-06 23:07
It's consistent with the behavior of generator expressions:
Variables used in the generator expression are evaluated lazily
when the __next__() method is called for the generator object
(in the same fashion as normal generators). However, the
leftmost for clause is immediately evaluated, so that an error
produced by it can be seen before any other possible error in
the code that handles the generator expression. Subsequent for
clauses cannot be evaluated immediately since they may depend
on the previous for loop. For example: (x*y for x in range(10)
for y in bar(x)).
History
Date
User
Action
Args
2022-04-11 14:58:49
admin
set
github: 75309
2017-08-06 23:07:21
eryksun
set
messages: +
2017-08-06 18:05:21
r.david.murray
set
messages: +
2017-08-06 14:26:54
eryksun
set
status: open -> closed
nosy: + eryksun
messages: +
resolution: not a bug
stage: resolved
2017-08-06 14:07:19
r.david.murray
set
nosy: + r.david.murray
messages: +
2017-08-06 13:17:16
ksqsf
create