2014-04-28

Bindings extraños en python

El comportamiento de locals() en python es extraño. ¿Por qué no me muestra siempre todas las variables por las que clausura? (pero sí muestra algunas :-/). ¿Como hago para obtenerlas todas?

Abajo pongo el POC que muestra que no anda como quiero:

>>> def foo():
...   a = 1
...   def bar():
...     print locals()
...   bar()
... 
>>> foo()
{}

Como ven, no muestra a como posible variable.

En cambio, en este ejemplo, que debería tener el mismo comportamiento, sí muestra a como variable.

>>> def foo():
...   a = 1
...   def bar():
...     a
...     print locals()
...   bar()
... 
>>> foo()
{'a': 1}


¿Cómo hago para armar el diccionario de las variables que se pueden usar en una función en python?

Todo esto lo probé en una consola corriendo python 2.7.6.

Happy hacking,
Aureliano.

4 comentarios:

Mario Vilas dijo...

Eso creo que es porque en el segundo ejemplo estás creando una variable "a" en el scope de la funcion embebida. Si es asi deberias ver este comportamiento en Python 2.5 tambien, pero no en versiones anteriores.

Mario Vilas dijo...

Otro ejemplo de comportamiento raro, tambien desde Python 2.5:

>>> def a():
... print map
... map = 0
... print map
...
>>> a()
Traceback (most recent call last):
File "", line 1, in
File "", line 2, in a
UnboundLocalError: local variable 'map' referenced before assignment

aurelianito dijo...

Mi pregunta es cómo hago para obtener el diccionario de todas las posibles rvalues en una función. Por ahora no sé cómo hacerlo. globals() + locals() no encuentra al "a" del primer ejemplo.

tenuki dijo...

Realmente no recuerdo haberme fijado alguna vez como funciona exactamente locals(). Pero creo que c/frame conoce a su locals.

Además, cuando se compila una función, se setupea, y me imagino que lo que te está pasando es que al compilar la primer función, como no la usa, no se preocupa por ponerla en ese locals en particular.

Entonces, creo que hay dos respuestas a tu pregunta:

La primera es: lo tenés con, como bien vos decís: globals() + locals() Ya que si usaran otra cosa, el compilador de funciones, la habría puesto en estos dics..

La segunda es: podrías ver que variables potenciales tendrías disponibles, usando traceback, para recorrer el stack-trace y tomar los locals de c/frame superior....... (y sus globals?)..