2010-05-01 8 views
17

En Python 2.6,¿Por qué se rompen los cierres dentro del ejecutivo?

>>> exec "print (lambda: a)()" in dict(a=2), {} 
2 
>>> exec "print (lambda: a)()" in globals(), {'a': 2} 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 1, in <module> 
    File "<string>", line 1, in <lambda> 
NameError: global name 'a' is not defined 
>>> exec "print (lambda: a).__closure__" in globals(), {'a': 2} 
None 

esperaba que imprime 2 dos veces, y luego imprimir una tupla con un solo cell. Es la misma situación en 3.1. ¿Que esta pasando?

Respuesta

24

Cuando pasa una cadena a exec o eval, compila esa cadena a un objeto de código antes de considerar globales o locales. Así, cuando decimos:

eval('lambda: a', ...) 

que significa:

eval(compile('lambda: a', '<stdin>', 'eval'), ...) 

No hay manera de compile saber que a es una freevar, por lo que compila a una referencia mundial:

>>> c= compile('lambda: a', '<stdin>', 'eval') 
>>> c.co_consts[0] 
<code object <lambda> at 0x7f36577330a8, file "<stdin>", line 1> 
>>> dis.dis(c.co_consts[0]) 
    1   0 LOAD_GLOBAL    0 (a) 
       3 RETURN_VALUE   

Por lo tanto, para hacerlo funcionar, debe poner a en los globales y no en los locales.

Sí, es un poco dudoso. Pero eso es exec y eval para ti, supongo ... no se supone que sean agradables.

+0

+1. He estado actualizando este hilo una vez por minuto desde que se publicó para encontrar la respuesta a este. Gracias a ti ahora soy libre de dejar mi computadora por un tiempo y salir y disfrutar del sol. ¡Gracias! ;) –

Cuestiones relacionadas