73

In debugging my code, I want to use a list comprehension. However, it seems I cannot evaluate a list comprehension from the debugger when I'm inside a function.

I am using Python 3.4.

Script contents:

$ cat test.py 
#!/usr/bin/python

def foo():
    x = [1, 2, 3, 3, 4]

    print(x)

foo()

Interactive debugging:

$ python3 -mpdb test.py                                                                                                                                           
> /tmp/test.py(3)<module>()
-> def foo():
(Pdb) step
> /tmp/test.py(8)<module>()
-> foo()
(Pdb) 
--Call--
> /tmp/test.py(3)foo()
-> def foo():
(Pdb) 
> /tmp/test.py(4)foo()
-> x = [1, 2, 3, 3, 4]
(Pdb) 
> /tmp/test.py(6)foo()
-> print(x)
(Pdb) p [x for _ in range(1)]
*** NameError: name 'x' is not defined
(Pdb) p x
[1, 2, 3, 3, 4]

Why is x unknown to the list comprehension? How could I evaluate a list comprehension from the debugger, or achieve an equivalent behaviour? Is this a bug, or is it some sort of fundamental limitation to the debugger?

6
  • Simpler example: p (lambda: x)()
    – Veedrac
    Commented Jun 10, 2014 at 19:35
  • 1
    The lambda pointer gave me an idea, and I found that the answers to this question apply equally here.
    – gerrit
    Commented Jun 10, 2014 at 19:49
  • 1
    Ah, that code.interact(locals=vars()) does exactly what my eval hack does.
    – Veedrac
    Commented Jun 10, 2014 at 19:54
  • Oh, and pdb even has an interact command, cool.
    – gerrit
    Commented Jun 11, 2014 at 15:14
  • 1
    Does this answer your question? iPython debugger raises `NameError: name ... is not defined`
    – Kobi T
    Commented May 18, 2021 at 7:14

3 Answers 3

104

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 foo
IndexError: 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]
>>> 
6
  • and for python2? Commented Feb 1, 2019 at 15:28
  • In Python 2 you don't have to do anything, it just works
    – Antimony
    Commented Feb 1, 2019 at 17:29
  • 14
    Had this problem for years, and thought it was generally just a bug that never got fixed.
    – Dave Liu
    Commented Sep 24, 2019 at 18:34
  • 10
    @DaveLiu Or is it a bug that never got fixed? The interact trick is refered here as a workaround.
    – iago-lito
    Commented Mar 31, 2020 at 8:55
  • I tried interact during a set_trace of qt app, and the shell become unresponsive, only responding with QCoreApplication::exec: The event loop is already running whenever I pressed enter. Commented Jan 31, 2021 at 22:50
14

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 lambda
dis.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]
1
  • 1
    Aah, and the reason it does work when it's on a module-level, is because x is not in locals(). I didn't get that at first.
    – gerrit
    Commented Jun 10, 2014 at 20:08
11

Running List Comprehensions that depend on Outer Context in the Debugger

The accepted solution did not work for me. Or, maybe my setting differs in a way I cannot distinguish from the question's setting. But, this is where google led me when I searched for a solution to running list comprehensions that depend on objects outside of the comprehension's scope. So, here's a solution for other folks with the same problem. Run the following line in the debugger.

globals().update(locals())

Then, your list comprehension should run without any problems. Source.

Not the answer you're looking for? Browse other questions tagged or ask your own question.