【问题标题】:List comprehension scope error from Python debugger来自 Python 调试器的列表理解范围错误
【发布时间】:2014-06-10 19:15:48
【问题描述】:

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

我正在使用 Python 3.4。

脚本内容

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

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

    print(x)

foo()

交互式调试:

$ 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]

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

【问题讨论】:

标签: python debugging python-3.x list-comprehension


【解决方案1】:

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

>>> 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]
>>> 

【讨论】:

  • 对于python2?
  • 在 Python 2 中你不需要做任何事情,它就可以工作
  • 这个问题已经困扰多年,并认为它通常只是一个从未修复的错误。
  • @DaveLiu 或者 它是一个从未得到修复的错误吗? interact 技巧被称为 here 作为解决方法。
  • 我在 qt 应用程序的 set_trace 期间尝试了 interact,但 shell 变得没有响应,只有在我按下回车时才以 QCoreApplication::exec: The event loop is already running 响应。
【解决方案2】:

pdb 似乎正在运行代码:

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

(或者甚至可能只是eval(string, globals(), locals()))。

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

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

但是当引入另一个范围时,例如 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
# The code of the internal lambda
dis.dis(compile("(lambda: x)()", "", "eval").co_consts[0])
#>>>   1           0 LOAD_GLOBAL              0 (x)
#>>>               3 RETURN_VALUE

注意LOAD_GLOBAL 是如何在本地范围内的x


这是一个完全愚蠢的破解方法:

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

【讨论】:

  • 啊,它在模块级别上工作的原因是因为x 不在locals() 中。一开始我没听懂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-04
  • 2020-09-01
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
相关资源
最近更新 更多