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.
Agradable. Nunca me di cuenta de eso. – zefciu
Parece ser el mismo problema que en esta pregunta: http://stackoverflow.com/questions/2749655/why-are-closures-broken-within-exec – interjay
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