2010-05-25 14 views
32

Estoy tratando de ejecutar un trozo de código python usando exec.globales y lugareños en python exec()

my_code = """ 
class A(object): 
    pass 

print 'locals: %s' % locals() 
print 'A: %s' % A 

class B(object): 
    a_ref = A 
""" 

global_env = {} 
local_env = {} 
my_code_AST = compile(my_code, "My Code", "exec") 
exec(my_code_AST, global_env, local_env) 

print local_env 

que se traduce en la siguiente salida

locals: {'A': <class 'A'>} 
A: <class 'A'> 
Traceback (most recent call last): 
    File "python_test.py", line 16, in <module> 
    exec(my_code_AST, global_env, local_env) 
    File "My Code", line 8, in <module> 
    File "My Code", line 9, in B 
NameError: name 'A' is not defined 

Sin embargo, si cambio el código para esto -

my_code = """ 
class A(object): 
    pass 

print 'locals: %s' % locals() 
print 'A: %s' % A 

class B(A): 
    pass 
""" 

global_env = {} 
local_env = {} 
my_code_AST = compile(my_code, "My Code", "exec") 
exec(my_code_AST, global_env, local_env) 

print local_env 

entonces funciona bien - dando el siguiente resultado -

locals: {'A': <class 'A'>} 
A: <class 'A'> 
{'A': <class 'A'>, 'B': <class 'B'>} 

Clearly A is pres y accesible: ¿qué está mal en la primera parte del código? Estoy usando 2.6.5, alegre,

Colin

* ACTUALIZACIÓN * 1

Si puedo comprobar los locales() dentro de la clase -

my_code = """ 
class A(object): 
    pass 

print 'locals: %s' % locals() 
print 'A: %s' % A 

class B(object): 
    print locals() 
    a_ref = A 
""" 

global_env = {} 
local_env = {} 
my_code_AST = compile(my_code, "My Code", "exec") 
exec(my_code_AST, global_env, local_env) 

print local_env 

entonces se convierte claro que los locales() no son los mismos en ambos lugares:

locals: {'A': <class 'A'>} 
A: <class 'A'> 
{'__module__': '__builtin__'} 
Traceback (most recent call last): 
    File "python_test.py", line 16, in <module> 
    exec(my_code_AST, global_env, local_env) 
    File "My Code", line 8, in <module> 
    File "My Code", line 10, in B 
NameError: name 'A' is not defined 

Sin embargo, si hago esto, no hay ningún problema -

def f(): 
    class A(object): 
    pass 

    class B(object): 
    a_ref = A 

f() 

print 'Finished OK' 

* ACTUALIZACIÓN 2 *

bien, por lo que los documentos aquí - http://docs.python.org/reference/executionmodel.html

'Una definición de clase es un ejecutable declaración que puede usar y definir nombres. Estas referencias siguen las reglas normales para la resolución de nombres. El espacio de nombres de la definición de clase se convierte en el diccionario de atributos de la clase. Los nombres definidos en el alcance de clase no son visibles en los métodos. '

Me parece que 'A' debe estar disponible como una variable libre dentro de la sentencia ejecutable que es la definición de B, y esto sucede cuando llamamos f() anterior, pero no cuando usamos exec () Esto puede ser más fácilmente se muestra con el siguiente -

my_code = """ 
class A(object): 
    pass 

print 'locals in body: %s' % locals() 
print 'A: %s' % A 

def f(): 
    print 'A in f: %s' % A 

f() 

class B(object): 
    a_ref = A 
""" 

que emite

locals in body: {'A': <class 'A'>} 
A: <class 'A'> 
Traceback (most recent call last): 
    File "python_test.py", line 20, in <module> 
    exec(my_code_AST, global_env, local_env) 
    File "My Code", line 11, in <module> 
    File "My Code", line 9, in f 
NameError: global name 'A' is not defined 

así que supongo que la nueva pregunta es - ¿por qué no son los locales que se exponen como variables libres en las funciones y definiciones de clases - Parece un escenario de cierre bastante estándar.

+0

Agradable. Nunca me di cuenta de eso. – zefciu

+0

Parece ser el mismo problema que en esta pregunta: http://stackoverflow.com/questions/2749655/why-are-closures-broken-within-exec – interjay

+0

gracias por el puntero - No soy un gurú de Python, pero parece que cuando imprimo locals(), A * has * sido compilado a una variable local, es decir, no sabe qué hacer con él. La respuesta en la pregunta que resaltó dice: 'No hay forma de que compile saber que a es un freevar, por lo que lo compila a una referencia global' El problema aquí parece ser que los locals() se redefinen dentro del cuerpo de B cuando se usa exec, pero no cuando se usa una función (ver la actualización en cuestión)? Sin embargo, podría ser fácilmente mi incomprensión de las implicaciones de esa respuesta ... – hawkett

Respuesta

17

Bueno, creo que es una falla de implementación o una decisión de diseño no documentada. El quid de la cuestión es que una operación de vinculación de nombres en el ámbito del módulo debe vincularse a una variable global. La forma en que se logra es que cuando en el nivel de módulo, globals() IS locales() (intente uno en el intérprete), cuando hace un enlace de nombre, lo asigna, como de costumbre, a los locales () diccionario, que también son los globales, por lo tanto, se crea una variable global.

Cuando busca una variable, primero comprueba sus locales actuales, y si no se encuentra el nombre, revisa recursivamente los locales que contienen ámbitos para el nombre de la variable hasta que encuentre la variable o alcance el módulo-scope. Si llega a eso, verifica los globales, que se supone que son los locales del alcance del módulo.

>>> exec(compile("import sys\nprint sys._getframe().f_code.co_name", "blah", "exec"), {}, {}) 
<module> 
>>> exec("a = 1\nclass A(object):\n\tprint a\n", {}, {}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 2, in <module> 
    File "<string>", line 3, in A 
NameError: name 'a' is not defined 
>>> d = {} 
>>> exec("a = 1\nclass A(object):\n\tprint a\n", d,d) 
1 

Este comportamiento es la razón por la herencia trabajó (la gente alcance el nombre de búsqueda utilizado de código objeto(), que de hecho tenía una en ella).

Al final, es un hack feo en la implementación de CPython, búsqueda global de envoltura especial. También provoca algunas situaciones artificiales sin sentido - ej .:

>>> def f(): 
...  global a 
...  a = 1 
... 
>>> f() 
>>> 'a' in locals() 
True 

Tenga en cuenta que todo esto es mi inferencia basada en jugar con el intérprete durante la lectura de la sección 4.1 (Naming y vinculante) de la referencia del lenguaje Python. Si bien esto no es definitivo (no abrí las fuentes de CPython), estoy bastante seguro de que estoy en lo correcto sobre el comportamiento.

+0

Ok, gracias por esa información, esa es una molestia :) la razón principal por la que quería usar locales como esa, era obtener todo lo que se definía en la cadena de código, sin todas las otras cosas que Python pone en los globales. Si 'print globals()' dentro de ese código, es un gran diccionario de cosas, lo cual tiene sentido, pero ahora no sé cómo hacer que las cosas que se definieron en la cadena de códigos en un diccionario: es decir, un diccionario con solo {'A', , 'B', } en él. No quiero tener que eliminar todo manualmente, y no sé de antemano qué hay en la cadena del código. – hawkett

+1

Voy a marcar que esta pregunta fue respondida: archivé un error de Python aquí - http://bugs.python.org/issue8819 - aplausos. – hawkett

+1

El error que archivé era un duplicado. He presentado un argumento para que esto se solucione en 2.6+ aquí - http://bugs.python.org/issue991196 – hawkett

2

Si su pregunta es cómo hacer que la declaración exec se comporte como el alcance del archivo, seguí algunas sugerencias en la pregunta vinculada y el error y lo puse en funcionamiento al pasar un solo diccionario para globales y locales. Aparentemente, el alcance del archivo es un caso especial en el que las declaraciones locales se ubican automáticamente en el ámbito global.

exec code in dict() 
6

Después print locals() y globals(), se encuentra la razón por la cual Exec tiros "no definido" excepción, y se puede probar este

d = dict(locals(), **globals()) 
exec (code, d, d) 
+0

Esta es la única respuesta en la que puedes enviar y recibir de vuelta a los globals/lugareños. Fantástica respuesta. A continuación, puede usar d como base para acceder a las variables del código secundario. d ['estado'] si tuvieras estado = {} en tu código. Gracias @Zoe – Dovy

1
my_code = """ 
class A(object): 
    pass 

class B(object): 
    a = A 
""" 

my_code_AST = compile(my_code, "My Code", "exec") 
extra_global = "hi" 
global_env = {} 
exec my_code_AST in global_env 
print "global_env.keys() =", global_env.keys() 
print "B.a =", global_env["B"].a 

impresiones

global_env.keys() = ['__builtins__', 'A', 'B'] 
B.a = <class 'A'> 

Hawkett , dices,

la razón principal por la que quería utilizar locales como esa, era obtener todas las cosas definidas en la cadena de código, sin todas las otras cosas que Python pone en las globales.

Con ejecutivo, si sus variables globales no tienen __builtins__ definido, ejecutivo añade un artículo, __builtins__ a sus variables globales, por lo que se obtiene A, B, y __builtins__. __builtins__ es un gran diccionario, pero siempre es el mismo elemento para eliminar (¡siempre que espere hasta que el código haya terminado de usarlo antes de eliminarlo!). Documentado bajo exec() here.

la documentación para eval bajo built in functions dicen

Si el diccionario está presente globales y carece de ‘órdenes internas’, las variables globales actuales se copian en variables globales antes se analiza la expresión.

Pero en realidad parece que sólo copiar __builtins__ en

(Y n.b. lo que los demás, dijo:. Bien establecidos globales y locales de la misma o decir exec my_code_AST in global_env sin local_env separada.)

Cuestiones relacionadas