List comprehension scope error from Python debugger List comprehension scope error from Python debugger python-3.x python-3.x

List comprehension scope error from Python debugger


In Python 3, you have to use the interact command in pdb before you can access any non-global variables due to a change in the way comprehensions are implemented.

>>> def foo(): [][0]... >>> foo()Traceback (most recent call last):  File "<stdin>", line 1, in <module>  File "<stdin>", line 1, in fooIndexError: list index out of range>>> import pdb;pdb.pm()> <stdin>(1)foo()(Pdb) x = 4(Pdb) [x for _ in range(2)]*** NameError: name 'x' is not defined(Pdb) interact*interactive*>>> [x for _ in range(2)][4, 4]>>> 


pdb seems to be running the code with:

eval(compiled_code, globals(), locals())

(or maybe even just eval(string, globals(), locals())).

Unfortunately, on compilation Python doesn't know of the local variables. This doesn't matter normally:

import dis
dis.dis(compile("x", "", "eval"))#>>>   1           0 LOAD_NAME                0 (x)#>>>               3 RETURN_VALUE

but when another scope is introduced, such as with a list comprehension of lambda, this compiles badly:

dis.dis(compile("(lambda: x)()", "", "eval"))#>>>   1           0 LOAD_CONST               0 (<code object <lambda> at 0x7fac20708d20, file "", line 1>)#>>>               3 LOAD_CONST               1 ('<lambda>')#>>>               6 MAKE_FUNCTION            0#>>>               9 CALL_FUNCTION            0 (0 positional, 0 keyword pair)#>>>              12 RETURN_VALUE
# The code of the internal lambdadis.dis(compile("(lambda: x)()", "", "eval").co_consts[0])#>>>   1           0 LOAD_GLOBAL              0 (x)#>>>               3 RETURN_VALUE

Note how that's a LOAD_GLOBAL where x is in the local scope.


Here's a totally stupid hack to get around it:

(Pdb) eval("(lambda: x)()", vars())[1, 2, 3, 3, 4]