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

时间:2014-06-10 19:15:49

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

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

我正在使用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?我如何从调试器中评估列表理解,或实现等效行为?这是一个错误,还是调试器的一些基本限制?

2 个答案:

答案 0 :(得分:29)

在Python 3中,您必须在pdb中使用services: # ... acme.kernel.listener.exception_listener: class: AppBundle\EventListener\ExceptionResponseListener tags: - {name: kernel.event_listener, event: kernel.exception, method: onKernelResponse} arguments: ['@router'] 命令,然后才能访问任何非全局变量,因为实现了理解的方式发生了变化。

interact

答案 1 :(得分:9)

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在本地范围内的位置{/ 1}}。


这是一个完全愚蠢的黑客攻击它:

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