Cualquier forma de modificar el diccionario de los locales?
-
11-09-2019 - |
Pregunta
locals
está construido en una función que devuelve un diccionario de valores locales. La documentación dice:
Advertencia
El contenido de este diccionario debe no ser modificado; cambios no pueden afectar a los valores de las variables locales utilizado por el intérprete.
Por desgracia, ejecutivo tiene el mismo problema en Python 3.0. ¿Hay alguna manera alrededor de esto?
Caso de Uso
Considere lo siguiente:
@depends("a", "b", "c", "d", "e", "f")
def test():
put_into_locals(test.dependencies)
depende de las tiendas de las cadenas provistas en sus argumentos en un test.dependences
lista. Estas cadenas son claves en un d
diccionario. Me gustaría ser capaz de escribir put_into_locals
para que pudiéramos tirar de los valores de d
y ponerlas en los locales. ¿Es esto posible?
Solución
Acabo de probar ejecutivo y funciona en Python 2.6.2
>>> def test():
... exec "a = 5"
... print a
...
>>> test()
5
Si está utilizando Python 3.x, que ya no funciona, porque los locales están optimizados como una matriz en tiempo de ejecución, en lugar de utilizar un diccionario.
Cuando Python detecta la "sentencia exec", que obligará a Python para cambiar el almacenamiento local de la matriz de diccionario. Sin embargo, ya que "exec" es una función en Python 3.x, el compilador no puede hacer esta distinción ya que el usuario podría haber hecho algo así como "exec = 123".
http://bugs.python.org/issue4831
Para modificar los locales de una función de la marcha no es posible sin varias consecuencias: normalmente, locales de funciones no se almacenan en una diccionario, pero una matriz, cuya índices se determinan en tiempo de compilación a partir de los lugares conocidos. esto choca al menos con nuevos agregados por los locales Exec. La vieja sentencia exec eludido esto, debido a que la compilador sabía que si un ejecutivo sin globales / Locales args se produjeron en una función, ese espacio de nombres sería "No optimizado", es decir, no utilizando la locales matriz. Desde exec () es ahora una función normal, el compilador no lo hace saben lo que "ejecutivo" puede estar unido a, y por lo tanto, no puede tratar es especialmente.
Otros consejos
Las variables locales son modificados por las instrucciones de asignación.
Si tiene claves de diccionarios que son cadenas, por favor no también hacer que las variables locales -. Simplemente los utilizan como claves del diccionario
Si es absolutamente debe han variables locales hacer esto.
def aFunction( a, b, c, d, e, f ):
# use a, b, c, d, e and f as local variables
aFunction( **someDictWithKeys_a_b_c_d_e_f )
que poblarán algunas variables locales de su diccionario sin hacer nada mágico.
Esto no es posible. Creo que esto es para permitir la optimización del rendimiento en el futuro. bytecode Python hace referencia a los locales por el índice, no por su nombre; Si se requirió locales () para tener permiso de escritura, podría evitar que los intérpretes de la implementación de algunas optimizaciones, o hacerlos más difícil.
Estoy bastante seguro de que no vas a encontrar ninguna API central que garantiza que puede editar los locales de este tipo, porque si esa API podía hacerlo, locals () no tendrían esta restricción tampoco.
No se olvide que todos los locales deben existir en tiempo de compilación; si hace referencia a un nombre que no está unido a un local en tiempo de compilación, el compilador asume que es un mundial. No se puede "crear" locales después de la compilación.
Consulte esta pregunta para una posible solución, pero es un corte serio y que realmente no quiere hacer eso.
Tenga en cuenta que hay un problema básico con el código de ejemplo:
@depends("a", "b", "c", "d", "e", "f")
def test():
put_into_locals(test.dependencies)
"test.dependencies"
no se refiere a "f.dependencies" donde F es la función actual; se hace referencia al valor mundial real "prueba". Esto significa que si se utiliza más de un decorador:
@memoize
@depends("a", "b", "c", "d", "e", "f")
def test():
put_into_locals(test.dependencies)
Se va a trabajar ya no, ya que "prueba" es memoize su función envuelto, no depende de. Python realmente necesita una forma de referirse a "la función que se está ejecutando-" (y clase).
Me almacenarlo en una variable:
refs = locals()
def set_pets():
global refs
animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
for i in range(len(animals)):
refs['pet_0%s' % i] = animals[i]
set_pets()
refs['pet_05']='bird'
print(pet_00, pet_02, pet_04, pet_01, pet_03, pet_05 )
>> dog fish monkey cat fox bird
Y si desea probar su dict antes de meterla en los locales ():
def set_pets():
global refs
sandbox = {}
animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
for i in range(len(animals)):
sandbox['pet_0%s' % i] = animals[i]
# Test sandboxed dict here
refs.update( sandbox )
Python 3.6.1 en MacOS Sierra
No estoy seguro de si está sujeto a las mismas restricciones, pero se puede obtener una referencia directa a la trama actual (y de ahí, las variables locales del diccionario) a través del módulo de inspección:
>>> import inspect
>>> inspect.currentframe().f_locals['foo'] = 'bar'
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect']
>>> foo
'bar'