¿Se puede actualizar alguno de estos en Python 3 y hacer que el script realmente funcione?
Charlie Parker
Respuestas:
172
Cada uno de estos devuelve un diccionario:
globals()siempre devuelve el diccionario del espacio de nombres del módulo
locals()siempre devuelve un diccionario del actual espacio de nombres
vars()devuelve un diccionario del espacio de nombres actual (si se llama sin argumento) o el diccionario del argumento.
localsy varspodría usar alguna explicación más. Si locals()se llama dentro de una función, actualiza un dict con los valores del espacio de nombres de la variable local actual (más cualquier variable de cierre) a partir de ese momento y lo devuelve. Varias llamadas a locals()en el mismo marco de pila devuelven el mismo dict cada vez: se adjunta al objeto de marco de pila como su f_localsatributo. El contenido del dict se actualiza en cada locals()llamada y f_localsacceso a cada atributo, pero solo en tales llamadas o accesos de atributo. No se actualiza automáticamente cuando se asignan variables, y la asignación de entradas en el dict no asignará las variables locales correspondientes:
import inspect
def f():
x =1
l = locals()print(l)
locals()print(l)
x =2print(x, l['x'])
l['x']=3print(x, l['x'])
inspect.currentframe().f_locals
print(x, l['x'])
f()
Nos da:
{'x':1}{'x':1,'l':{...}}212322
El primero print(l)solo muestra una 'x'entrada, porque la asignación a locurre después de la locals()llamada. El segundo print(l), después de llamar locals()nuevamente, muestra una lentrada, a pesar de que no guardamos el valor de retorno. El tercer y cuarto prints muestran que la asignación de variables no se actualiza ly viceversa, pero después de acceder f_locals, las variables locales se copian locals()nuevamente.
Dos notas:
Este comportamiento es específico de CPython: otras Pythons pueden permitir que las actualizaciones vuelvan automáticamente al espacio de nombres local.
En CPython 2.x es posible hacer que esto funcione poniendo una exec "pass"línea en la función. Esto cambia la función a un modo de ejecución más antiguo y más lento que usa el locals()dict como la representación canónica de las variables locales.
Si locals()se llama fuera de una función, devuelve el diccionario real que es el espacio de nombres actual. Otros cambios en el espacio de nombres se reflejan en el diccionario, y los cambios en el diccionario se reflejan en el espacio de nombres:
classTest(object):
a ='one'
b ='two'
huh = locals()
c ='three'
huh['d']='four'print huh
Hasta ahora, todo lo que he dicho locals()también es cierto para vars()... aquí está la diferencia: vars()acepta un solo objeto como argumento, y si le da un objeto, devuelve el __dict__de ese objeto. Para un objeto típico, __dict__es donde se almacena la mayoría de sus datos de atributos. Esto incluye variables de clase y módulos globales:
classTest(object):
a ='one'
b ='two'def frobber(self):print self.c
t =Test()
huh = vars(t)
huh['c']='three'
t.frobber()
lo que nos da:
three
Tenga en cuenta que una función __dict__es su espacio de nombres de atributo, no variables locales. No tendría sentido que una función __dict__almacene variables locales, ya que la recursión y el subprocesamiento múltiple significan que puede haber múltiples llamadas a una función al mismo tiempo, cada una con sus propios locales:
Aquí, se fllama recursivamente, por lo que las llamadas internas y externas se superponen. Cada uno ve sus propias variables locales cuando llama locals(), pero ambas llamadas ven lo mismo f.__dict__y f.__dict__no tienen ninguna variable local.
La parte "y las asignaciones al diccionario no se reflejan en el espacio de nombres local real" podrían estar un poco definidas .
Sven Marnach
Por extraño que parezca, se puede acceder a las variables agregadas a una vars()o locals()diccionario llamado dentro de una función si se utiliza eval(). EG: def test(): huh = locals(); huh['d'] = 4; print eval('d')imprime 4 cuando test()se ejecuta!
Mark Mikofski
1
En realidad, la asignación a dict(devuelta por locals()) se refleja en el espacio de nombres local y los cambios en el espacio de nombres local se reflejan en dict(en mi python). Lo único es que la especificación no garantiza este comportamiento.
skyking
El uso del alcance del nombre de término me parece más fácil que el espacio de nombres .
intercambio excesivo
1
@overexchange: import thisy en googlesite:docs.python.org namespace
Respuestas:
Cada uno de estos devuelve un diccionario:
globals()
siempre devuelve el diccionario del espacio de nombres del módulolocals()
siempre devuelve un diccionario del actual espacio de nombresvars()
devuelve un diccionario del espacio de nombres actual (si se llama sin argumento) o el diccionario del argumento.locals
yvars
podría usar alguna explicación más. Silocals()
se llama dentro de una función, actualiza un dict con los valores del espacio de nombres de la variable local actual (más cualquier variable de cierre) a partir de ese momento y lo devuelve. Varias llamadas alocals()
en el mismo marco de pila devuelven el mismo dict cada vez: se adjunta al objeto de marco de pila como suf_locals
atributo. El contenido del dict se actualiza en cadalocals()
llamada yf_locals
acceso a cada atributo, pero solo en tales llamadas o accesos de atributo. No se actualiza automáticamente cuando se asignan variables, y la asignación de entradas en el dict no asignará las variables locales correspondientes:Nos da:
El primero
print(l)
solo muestra una'x'
entrada, porque la asignación al
ocurre después de lalocals()
llamada. El segundoprint(l)
, después de llamarlocals()
nuevamente, muestra unal
entrada, a pesar de que no guardamos el valor de retorno. El tercer y cuartoprint
s muestran que la asignación de variables no se actualizal
y viceversa, pero después de accederf_locals
, las variables locales se copianlocals()
nuevamente.Dos notas:
exec "pass"
línea en la función. Esto cambia la función a un modo de ejecución más antiguo y más lento que usa ellocals()
dict como la representación canónica de las variables locales.Si
locals()
se llama fuera de una función, devuelve el diccionario real que es el espacio de nombres actual. Otros cambios en el espacio de nombres se reflejan en el diccionario, y los cambios en el diccionario se reflejan en el espacio de nombres:Nos da:
Hasta ahora, todo lo que he dicho
locals()
también es cierto paravars()
... aquí está la diferencia:vars()
acepta un solo objeto como argumento, y si le da un objeto, devuelve el__dict__
de ese objeto. Para un objeto típico,__dict__
es donde se almacena la mayoría de sus datos de atributos. Esto incluye variables de clase y módulos globales:lo que nos da:
Tenga en cuenta que una función
__dict__
es su espacio de nombres de atributo, no variables locales. No tendría sentido que una función__dict__
almacene variables locales, ya que la recursión y el subprocesamiento múltiple significan que puede haber múltiples llamadas a una función al mismo tiempo, cada una con sus propios locales:lo que nos da:
Aquí, se
f
llama recursivamente, por lo que las llamadas internas y externas se superponen. Cada uno ve sus propias variables locales cuando llamalocals()
, pero ambas llamadas ven lo mismof.__dict__
yf.__dict__
no tienen ninguna variable local.fuente
vars()
olocals()
diccionario llamado dentro de una función si se utilizaeval()
. EG:def test(): huh = locals(); huh['d'] = 4; print eval('d')
imprime 4 cuandotest()
se ejecuta!dict
(devuelta porlocals()
) se refleja en el espacio de nombres local y los cambios en el espacio de nombres local se reflejan endict
(en mi python). Lo único es que la especificación no garantiza este comportamiento.import this
y en googlesite:docs.python.org namespace