studio - pdb python
Enumere el error del alcance de la comprensiĆ³n del depurador de Python (2)
En Python 3, debe utilizar el comando interact
en pdb antes de poder acceder a cualquier variable no global debido a un cambio en la forma en que se implementan las comprensiones.
>>> 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]
>>>
Al depurar mi código, quiero usar una lista de comprensión. Sin embargo, parece que no puedo evaluar una lista de comprensión del depurador cuando estoy dentro de una función.
Estoy usando Python 3.4.
Contenidos del guión :
$ cat test.py
#!/usr/bin/python
def foo():
x = [1, 2, 3, 3, 4]
print(x)
foo()
Depuración interactiva:
$ 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]
¿Por qué x
es desconocido para la lista de comprensión? ¿Cómo podría evaluar una lista de comprensión del depurador o lograr un comportamiento equivalente? ¿Es esto un error, o es una limitación fundamental para el depurador?
pdb
parece estar ejecutando el código con:
eval(compiled_code, globals(), locals())
(o tal vez solo eval(string, globals(), locals())
).
Desafortunadamente, en la compilación Python no conoce las variables locales. Esto no importa normalmente:
import dis
dis.dis(compile("x", "", "eval"))
#>>> 1 0 LOAD_NAME 0 (x)
#>>> 3 RETURN_VALUE
pero cuando se introduce otro ámbito, como con una lista de comprensión de lambda
, esto se compila mal:
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
Tenga en cuenta que es un LOAD_GLOBAL
donde x
está en el ámbito local.
Aquí hay un truco totalmente estúpido para evitarlo:
(Pdb) eval("(lambda: x)()", vars())
[1, 2, 3, 3, 4]