Alcance dentro de Python exec

Cuando una variable/función se define dentro de un exec parece ir a la locals() en lugar de la globals() ¿Cómo puedo cambiar este comportamiento? Esto solo sucede cuando pasa los diccionarios globales y locales al exec.

Ejemplo:

exec("""
a = 2

def foo():
    print a

foo()""") in {},{}

Cuando intentas esto:

NameError: global name 'a' is not defined

preguntado el 04 de julio de 12 a las 10:07

2 Respuestas

A mí también me resulta extraño a primera vista. Pero con un poco más de salida encontré la razón:

>>> g, l = {}, {}
>>> print id(g), id(l)
12311984 12310688
>>>
>>> exec '''
... a = 2
... print 'a' in globals(), 'a' in locals(), id(globals()), id(locals())
... def f():
...     print 'a' in globals(), 'a' in locals(), id(globals()), id(locals())
... f()
... ''' in g, l
False True 12311984 12310688
False False 12311984 12311264

Como se dice en http://effbot.org/pyfaq/what-are-the-rules-for-local-and-global-variables-in-python.htm:

En Python, las variables a las que solo se hace referencia dentro de una función son implícitamente globales. Si a una variable se le asigna un nuevo valor en cualquier parte del cuerpo de la función, se supone que es local. Si alguna vez se le asigna un nuevo valor a una variable dentro de la función, la variable es implícitamente local y debe declararla explícitamente como global.

Entonces, una solución es usar el mismo dict para globales y locales:

>>> l = {}
>>> exec '''
... a = 2
... def f():
...     print a
... f()
... ''' in l, l
2

Respondido 04 Jul 12, 11:07

¡Gracias! Otra solución es pasar solo el dict global. Pero es bueno saber la razón. - Josep Virgili Llop

If a no es global, hazlo global...

exec("""
global a
a = 2

def foo():
    print a

foo()""") in {}, {}

Respondido 04 Jul 12, 10:07

Sí, pero el código dentro del exec está escrito por un tercero que no sabe que va dentro de un exec por lo que no ven ninguna razón para usar global. - Josep Virgili Llop

Entonces, ¿por qué no lo mencionaste en la pregunta? Pensé que eras un principiante (11 repeticiones) que simplemente no sabía sobre global. - BrtH

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.