Jede Art und Weise Einheimischen Wörterbuch zu ändern?
-
11-09-2019 - |
Frage
locals
ist eine integrierte Funktion, die ein Wörterbuch der lokalen Werte zurückgibt. Die Dokumentation sagt:
Warnung
Der Inhalt dieses Wörterbuch sollte , Nicht modifiziert werden, Änderungen können nicht Auswirkungen auf die Werte von lokalen Variablen vom Interpreter verwendet.
Leider exec hat das gleiche Problem in Python 3.0. Gibt es eine Möglichkeit Runde das?
Use Case
Bedenken Sie:
@depends("a", "b", "c", "d", "e", "f")
def test():
put_into_locals(test.dependencies)
hängt speichert die Saiten in ihre Argumente in einer Liste test.dependences
zur Verfügung gestellt. Diese Strings sind die Schlüssel in einem Wörterbuch d
. Ich möchte in der Lage sein können put_into_locals
schreiben, so dass wir die Werte aus d
ziehen konnte und sie in die Einheimischen setzen. Ist das möglich?
Lösung
I exec nur getestet und es funktioniert in Python 2.6.2
>>> def test():
... exec "a = 5"
... print a
...
>>> test()
5
Wenn Sie Python 3.x verwenden, ist es nicht mehr arbeiten, weil Einheimische als Array zur Laufzeit optimiert werden, anstatt ein Wörterbuch zu verwenden.
Wenn Python die „exec-Anweisung“ erkennt, wird es Python zwingt lokale Speicherung von Array-Wörterbuch zu wechseln. Da jedoch „exec“ eine Funktion in Python 3.x ist, kann der Compiler diese Unterscheidung nicht machen, da der Benutzer so etwas wie „exec = 123“ getan haben könnte.
http://bugs.python.org/issue4831
die Einheimischen einer Funktion ändern auf die Fliege ist nicht möglich, ohne mehrere Konsequenzen: in der Regel, Funktion Einheimischen sind nicht in einer gespeicherten Wörterbuch, aber ein Array, das Indizes werden zum Zeitpunkt der Kompilierung bestimmt von den bekannten Schauplätzen. Dies kollidiert zumindest mit neuen Einheimischen hinzugefügt von exec. Die alte exec umgangen dies, weil die Compiler wusste, dass, wenn eine exec ohne Globals / Einheimische args ereignete sich in einem Funktion, wäre das Namespace „Nicht optimiert“, das heißt nicht unter Verwendung des Einheimische Array. Da exec () ist jetzt ein normale Funktion, funktioniert der Compiler nicht wissen, was „exec“ gebunden sein kann, und kann daher nicht behandelt, ist speziell.
Andere Tipps
Die lokalen Variablen werden durch Zuweisungen geändert.
Wenn Sie Dictionary-Schlüssel haben, die Saiten sind, bitte sie lokale Variablen nicht auch machen -. Nur sie als Dictionary-Schlüssel verwenden
Wenn Sie unbedingt muss haben lokale Variablen tun.
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 )
Das wird einige lokalen Variablen aus dem Wörterbuch füllen, ohne magisch etwas zu tun.
Dies ist nicht möglich. Ich denke, das später für Performance-Optimierungen zu ermöglichen ist. Python-Bytecode verweist Einheimischen durch den Index, nicht namentlich; wenn Einheimische () war erforderlich, um beschreibbar zu sein, könnte es Dolmetscher verhindern, dass einige Optimierungen implementieren oder sie erschweren.
Ich bin ziemlich sicher, du wirst keinen Kern-API finden, die Sie so garantiert können Einheimischer bearbeiten, denn wenn die API es tun könnte, Einheimische () würde diese Einschränkung nicht hat entweder.
Vergessen Sie nicht, dass alle Einheimischen zur Compile-Zeit vorhanden sein muss; wenn Sie einen Namen verweisen, die nicht zu einem lokalen zur Compile-Zeit gebunden ist, nimmt der Compiler es eine global ist. Sie können nicht „schaffen“ Einheimischen nach der Kompilierung.
Ich würde speichern Sie es in einer Variablen:
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
Und wenn Sie möchten, dass Ihre dict testen, bevor es in den Einheimischen setzen ():
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 auf MacOS Sierra
Ich bin mir nicht sicher, ob es die gleichen Einschränkungen unterworfen ist, aber Sie können einen direkten Verweis auf den aktuellen Rahmen erhalten (und von dort die lokalen Variablen Wörterbuch) durch das Modul überprüfen:
>>> import inspect
>>> inspect.currentframe().f_locals['foo'] = 'bar'
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect']
>>> foo
'bar'