2014-06-10 21 views
12

Nel debug del mio codice, voglio usare una comprensione di lista. Tuttavia, sembra che non possa valutare una comprensione di lista dal debugger quando sono all'interno di una funzione.Errore di scope di comprensione degli elenchi dal debugger Python

Sto usando Python 3.4.

contenuto dello script:

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

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

    print(x) 

foo() 

debug interattivo:

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

Perché è x sconosciuto al di lista? Come posso valutare la comprensione di una lista dal debugger o ottenere un comportamento equivalente? È un bug o è una sorta di limite fondamentale per il debugger?

+0

@Veedrac Huh, ho appena realizzato in un piccolo script di test, che lì funziona. Farò un po 'di scavo e tornerò con un piccolo script eseguibile! – gerrit

+1

@Veedrac Modificato per aggiungere esattamente questo. – gerrit

+0

Esempio più semplice: 'p (lambda: x)()' – Veedrac

risposta

11

In Python 3, è necessario utilizzare il comando interact nel PDB prima di poter accedere a qualsiasi variabile non globali a causa di un cambiamento nel modo in cui le comprensioni sono implementate.

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

pdb sembra essere in esecuzione il codice con:

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

(o forse anche solo eval(string, globals(), locals())).

Sfortunatamente, nella compilazione Python non conosce le variabili locali. Questo non importa normalmente:

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

ma quando viene introdotto un altro ambito, come ad esempio con una lista di comprensione di lambda, questo compila male:

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 

Nota come questo è un LOAD_GLOBAL dove x è nel locale sco pe.


Ecco un trucco totalmente stupido per aggirare l'ostacolo:

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

Aah, e il motivo per cui funziona quando è a livello di modulo, è perché 'x' non è in' locals() '. All'inizio non l'ho capito. – gerrit

Problemi correlati