matplot chart python python-3.x generator pdb ipdb

python - chart - title matplot



Posible error en el módulo pdb en Python 3 al usar generadores de listas (3)

Funciona perfectamente bien:

>>> import pdb >>> def f(seq): ... pdb.set_trace() ... >>> f([1,2,3]) --Return-- > <stdin>(2)f()->None (Pdb) [x for x in seq] [1, 2, 3] (Pdb) [x in seq for x in seq] [True, True, True]

Sin mostrar lo que realmente está haciendo, nadie puede decirle por qué en su caso específico obtuvo un NameError .

TL; DR en python3 list-comprensión son en realidad funciones con su propio marco de pila, y no se puede acceder a la variable seq , que es un argumento de test , desde los marcos de pila internos. En su lugar, se trata como un global (y, por lo tanto, no se encuentra).

Lo que ves es la implementación diferente de list-comprensión en python2 vs python3. En Python 2, la lista de comprensión es en realidad una mano corta para el bucle for , y puedes ver esto claramente en el código de bytes:

>>> def test(): [x in seq for x in seq] ... >>> dis.dis(test) 1 0 BUILD_LIST 0 3 LOAD_GLOBAL 0 (seq) 6 GET_ITER >> 7 FOR_ITER 18 (to 28) 10 STORE_FAST 0 (x) 13 LOAD_FAST 0 (x) 16 LOAD_GLOBAL 0 (seq) 19 COMPARE_OP 6 (in) 22 LIST_APPEND 2 25 JUMP_ABSOLUTE 7 >> 28 POP_TOP 29 LOAD_CONST 0 (None) 32 RETURN_VALUE

Observe cómo el FOR_ITER contiene un bucle FOR_ITER . Por otro lado, en python3 list-comprensión son en realidad funciones con su propio marco de pila:

>>> def test(): [x in seq2 for x in seq] ... >>> dis.dis(test) 1 0 LOAD_CONST 1 (<code object <listcomp> at 0xb6fef160, file "<stdin>", line 1>) 3 MAKE_FUNCTION 0 6 LOAD_GLOBAL 0 (seq) 9 GET_ITER 10 CALL_FUNCTION 1 13 POP_TOP 14 LOAD_CONST 0 (None) 17 RETURN_VALUE

Como puede ver, aquí no hay FOR_ITER , en su lugar hay un bytecodes MAKE_FUNCTION y CALL_FUNCTION . Si examinamos el código de la lista-comprensión podemos entender cómo se configuran los enlaces:

>>> test.__code__.co_consts[1] <code object <listcomp> at 0xb6fef160, file "<stdin>", line 1> >>> test.__code__.co_consts[1].co_argcount # it has one argument 1 >>> test.__code__.co_consts[1].co_names # global variables (''seq2'',) >>> test.__code__.co_consts[1].co_varnames # local variables (''.0'', ''x'')

Aquí .0 es el único argumento de la función. x es la variable local del bucle y seq2 es una variable global . Tenga en cuenta que .0 , el argumento de comprensión de lista, es el iterable obtenido de seq , no seq . (Ver el código de operación GET_ITER en la salida de dis arriba). Esto es más claro con un ejemplo más complejo:

>>> def test(): ... [x in seq for x in zip(seq, a)] ... >>> dis.dis(test) 2 0 LOAD_CONST 1 (<code object <listcomp> at 0xb7196f70, file "<stdin>", line 2>) 3 MAKE_FUNCTION 0 6 LOAD_GLOBAL 0 (zip) 9 LOAD_GLOBAL 1 (seq) 12 LOAD_GLOBAL 2 (a) 15 CALL_FUNCTION 2 18 GET_ITER 19 CALL_FUNCTION 1 22 POP_TOP 23 LOAD_CONST 0 (None) 26 RETURN_VALUE >>> test.__code__.co_consts[1].co_varnames (''.0'', ''x'')

Aquí puede ver que el único argumento para la comprensión de lista, siempre denotado por .0 , es el iterable obtenido de zip(seq, a) . seq y a sí mismos no se pasan a la lista-comprensión. Solo se pasa iter(zip(seq, a)) dentro de la comprensión de la lista.

Otra observación que debemos hacer es que, cuando ejecuta pdb , no puede acceder al contexto de la función actual desde las funciones que desea definir. Por ejemplo, el siguiente código falla tanto en python2 como en python3:

>>> import pdb >>> def test(seq): pdb.set_trace() ... >>> test([1,2,3]) --Return-- > <stdin>(1)test()->None (Pdb) def test2(): print(seq) (Pdb) test2() *** NameError: global name ''seq'' is not defined

Falla porque al definir test2 la variable seq se trata como una variable global , pero en realidad es una variable local dentro de la función de test , por lo que no es accesible.

El comportamiento que ves es similar al siguiente escenario:

#python 2 no error >>> class A(object): ... x = 1 ... L = [x for _ in range(3)] ... >>> #python3 error! >>> class A(object): ... x = 1 ... L = [x for _ in range(3)] ... Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in A File "<stdin>", line 3, in <listcomp> NameError: global name ''x'' is not defined

El primero no da un error porque es mayormente equivalente a:

>>> class A(object): ... x = 1 ... L = [] ... for _ in range(3): L.append(x) ...

Dado que la lista de comprensión está "expandida" en el bytecode. En python3 falla porque en realidad estás definiendo una función y no puedes acceder al alcance de la clase desde un alcance de función anidado:

>>> class A(object): ... x = 1 ... def test(): ... print(x) ... test() ... Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in A File "<stdin>", line 4, in test NameError: global name ''x'' is not defined

Tenga en cuenta que los genexp se implementan como funciones en python2, y de hecho se ve un comportamiento similar con ellos (tanto en python2 como en python3):

>>> import pdb >>> def test(seq): pdb.set_trace() ... >>> test([1,2,3]) --Return-- > <stdin>(1)test()->None (Pdb) list(x in seq for x in seq) *** Error in argument: ''(x in seq for x in seq)''

Aquí pdb no le da más detalles, pero la falla ocurre por la misma razón.

En conclusión: no es un error en pdb sino la forma en que Python implementa los ámbitos. AFAIK cambiar esto para permitir lo que está intentando hacer en pdb requeriría algunos cambios importantes en la forma en que se tratan las funciones y no sé si esto se puede hacer sin modificar el intérprete.

Tenga en cuenta que al usar listas-comprensión anidadas, el bucle anidado se expande en código de bytes como las listas-comprensión en python2:

>>> import dis >>> def test(): [x + y for x in seq1 for y in seq2] ... >>> dis.dis(test) 1 0 LOAD_CONST 1 (<code object <listcomp> at 0xb71bf5c0, file "<stdin>", line 1>) 3 MAKE_FUNCTION 0 6 LOAD_GLOBAL 0 (seq1) 9 GET_ITER 10 CALL_FUNCTION 1 13 POP_TOP 14 LOAD_CONST 0 (None) 17 RETURN_VALUE >>> # The only argument to the listcomp is seq1 >>> import types >>> func = types.FunctionType(test.__code__.co_consts[1], globals()) >>> dis.dis(func) 1 0 BUILD_LIST 0 3 LOAD_FAST 0 (.0) >> 6 FOR_ITER 29 (to 38) 9 STORE_FAST 1 (x) 12 LOAD_GLOBAL 0 (seq2) 15 GET_ITER >> 16 FOR_ITER 16 (to 35) 19 STORE_FAST 2 (y) 22 LOAD_FAST 1 (x) 25 LOAD_FAST 2 (y) 28 BINARY_ADD 29 LIST_APPEND 3 32 JUMP_ABSOLUTE 16 >> 35 JUMP_ABSOLUTE 6 >> 38 RETURN_VALUE

Como puede ver, el bytecode para listcomp tiene un FOR_ITER explícito sobre seq2 . Este FOR_ITER explícito está dentro de la función listcomp y, por lo tanto, las restricciones sobre los ámbitos aún se aplican (por ejemplo, seq2 se carga como un global).

Y de hecho podemos confirmar esto usando pdb :

>>> import pdb >>> def test(seq1, seq2): pdb.set_trace() ... >>> test([1,2,3], [4,5,6]) --Return-- > <stdin>(1)test()->None (Pdb) [x + y for x in seq1 for y in seq2] *** NameError: global name ''seq2'' is not defined (Pdb) [x + y for x in non_existent for y in seq2] *** NameError: name ''non_existent'' is not defined

Observe cómo el NameError se trata de seq2 y no seq1 (que se pasa como argumento de la función), y observe cómo el cambio del primer nombre iterable a algo que no existe cambia el NameError (lo que significa que en el primer caso se pasó con éxito) seq1 ) .

Después de ejecutar este código en Python 3:

import pdb def foo(): nums = [1, 2, 3] a = 5 pdb.set_trace() foo()

Las siguientes expresiones funcionan:

(Pdb) print(nums) [1, 2, 3] (Pdb) print(a) 5 (Pdb) [x for x in nums] [1, 2, 3]

pero la siguiente expresión falla:

(Pdb) [x*a for x in nums] *** NameError: global name ''a'' is not defined

Lo anterior funciona bien en Python 2.7.

¿Es esto un error o me falta algo?

Actualización : ver la nueva respuesta aceptada. Esto fue realmente un error (o un diseño problemático) que se ha abordado ahora mediante la introducción de un nuevo comando y modo en pdb.


Simplemente no puedo entender por qué tendría que hacer lo anterior si está buscando producir una lista de Trues para cada elemento en seq, entonces por qué no [Verdadero para x en seq] - Supongo que necesita asignar un local Copia primero antes de probar este tipo de cosas.


si escribe interact en su sesión de [i] pdb, obtiene una sesión interactiva y las comprensiones de lista funcionan como se espera en este modo

fuente: http://bugs.python.org/msg215963