从Python调试器列出理解范围错误

ger*_*rit 26 python debugging list-comprehension python-3.x

在调试我的代码时,我想使用列表理解.但是,当我在函数内部时,似乎无法从调试器中评估列表理解.

我使用的是Python 3.4.

脚本内容:

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

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

    print(x)

foo()
Run Code Online (Sandbox Code Playgroud)

交互式调试:

$ 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]
Run Code Online (Sandbox Code Playgroud)

为什么x列表理解未知?我如何从调试器中评估列表理解,或实现等效行为?这是一个错误,还是调试器的某种基本限制?

Ant*_*ony 38

在Python 3中,您必须先使用interactpdb中的命令,然后才能访问任何非全局变量,因为实现了理解的方式发生了变化.

>>> 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]
>>> 
Run Code Online (Sandbox Code Playgroud)

  • 这个问题已经存在很多年了,并且认为这通常只是一个从未得到修复的错误。 (8认同)
  • @DaveLiu 或者*是*它是一个从未修复的错误?[此处](https://bugs.python.org/issue38970#msg357840) 引用了“interact”技巧作为解决方法。 (5认同)

lan*_*don 11

在调试器中运行依赖于外部上下文的列表推导式

接受的解决方案对我来说不起作用。或者,也许我的设置与问题的设置不同,我无法区分。但是,当我搜索运行依赖于推导范围之外的对象的列表推导式的解决方案时,这就是谷歌引导我的地方。因此,这里为其他遇到同样问题的人提供了一个解决方案。在调试器中运行以下行。

globals().update(locals())
Run Code Online (Sandbox Code Playgroud)

然后,您的列表理解应该可以毫无问题地运行。来源。


Vee*_*rac 9

pdb 似乎运行代码:

eval(compiled_code, globals(), locals())
Run Code Online (Sandbox Code Playgroud)

(或者甚至只是eval(string, globals(), locals())).

不幸的是,在编译时Python不知道局部变量.这通常无关紧要:

import dis
Run Code Online (Sandbox Code Playgroud)
dis.dis(compile("x", "", "eval"))
#>>>   1           0 LOAD_NAME                0 (x)
#>>>               3 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

但是当引入另一个范围时,例如列表理解lambda,这会严重编译:

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
Run Code Online (Sandbox Code Playgroud)
# The code of the internal lambda
dis.dis(compile("(lambda: x)()", "", "eval").co_consts[0])
#>>>   1           0 LOAD_GLOBAL              0 (x)
#>>>               3 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

请注意如何将是一个LOAD_GLOBAL地方x是在局部范围内.


这是一个完全愚蠢的黑客来解决它:

(Pdb) eval("(lambda: x)()", vars())
[1, 2, 3, 3, 4]
Run Code Online (Sandbox Code Playgroud)