2009-09-23 16 views

Antwort

27

Dieses Problem diskutiert wird, etwas in den Python3 bug list. Letztlich, um dieses Verhalten zu bekommen, was Sie tun müssen:

def foo(): 
    ldict = locals() 
    exec("a=3",globals(),ldict) 
    a = ldict['a'] 
    print(a) 

Und wenn Sie the Python3 documentation on exec überprüfen, werden Sie die folgende Anmerkung sehen:

The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

zurück zu a specific message on the bug report Bezug Georg Brandl sagt:

To modify the locals of a function on the fly is not possible without several consequences: normally, function locals are not stored in a dictionary, but an array, whose indices are determined at compile time from the known locales. This collides at least with new locals added by exec. The old exec statement circumvented this, because the compiler knew that if an exec without globals/locals args occurred in a function, that namespace would be "unoptimized", i.e. not using the locals array. Since exec() is now a normal function, the compiler does not know what "exec" may be bound to, and therefore can not treat is specially.

Der Schwerpunkt liegt bei mir.

Also das Wesentliche davon ist, dass Python3 kann besser die Verwendung von lokalen Variablen von nicht dieses Verhalten standardmäßig zu ermöglichen.

Und der Vollständigkeit halber, wie oben in den Kommentaren erwähnt, diese tut Arbeit wie in Python 2.x erwartet:

Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
[GCC 4.3.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> def f(): 
...  a = 1 
...  exec "a=3" 
...  print a 
... 
>>> f() 
3 
+0

Ich sehe, es ist ein Problem mit Locals(), die in Python 2.X aus exec gehackt wurde. Dieses Problem ist nicht so eindeutig dokumentiert, wie ich es mir gewünscht hätte. Auf Exec/Locals, die von 2.X auf 3.X wechseln, sollte irgendwo http://docs.python.org/3.1/library/functions.html#exec hingewiesen werden, und ich denke, dass exec einen Bequemlichkeitsparameter haben sollte, der diese Optimierung umgeht. .. – ubershmekel

+0

@MarkRushakoff Ich bekomme einen Fehler mit Ihrer Implementierung in der Zeile von exec: TypeError: 'dict' Objekt ist nicht aufrufbar – Leo

+0

@Leo sollte es nicht 'ldict', nicht' dict' sein? Wie auch immer, ich arbeite nicht mehr viel in Python, wenn das nicht stimmt, wird hoffentlich jemand anderes reinhören. –

0

Der Grund, dass Sie nicht auf lokale Variablen innerhalb einer FunktionVerwendung ändern könnenauf diese Weise und warum exec Tat so, wie es funktioniert kann wie folgt zusammengefasst werden:

  1. exec ist eine Funktion, die mit dem Umfang des innersten Bereichs, in dem es heißt seine lokale scape teilt.
  2. Wenn Sie ein neues Objekt innerhalb des Bereichs einer Funktion definieren, wird es in seinem lokalen Namespace zugänglich sein, d. H. Es wird das local() Wörterbuch ändern. Wenn Sie ein neues Objekt in exec definieren, was es tut, entspricht in etwa folgenden:

from copy import copy 
class exec_type: 
    def __init__(self, *args, **kwargs): 
     # default initializations 
     # ... 
     self.temp = copy(locals()) 

    def __setitem__(self, key, value): 
     if var not in locals(): 
      set_local(key, value) 
     self.temp[key] = value 

temp ein temporären Namensraum ist, der nach jeder Instanziierung zurückzusetzt. (Jedes Mal rufen Sie die exec)


  1. Python beginnt für die Namen von lokalen Namensraum nach oben. Es ist bekannt als LEGB-Art. Python beginnt mit Local namespce und sucht dann in den Enclosing-Bereichen, dann Global und am Ende nach den Namen im Buit-In-Namespace.

Ein umfassenderes Beispiel würden wir so etwas wie folgt vor:

g_var = 5 

def test(): 
    l_var = 10 
    print(locals()) 
    exec("print(locals())") 
    exec("g_var = 222") 
    exec("l_var = 111") 
    exec("print(locals())") 

    exec("l_var = 111; print(locals())") 

    exec("print(locals())") 
    print(locals()) 
    def inner(): 
     exec("print(locals())") 
     exec("inner_var = 100") 
     exec("print(locals())") 
     exec("print([i for i in globals() if '__' not in i])") 

    print("Inner function: ") 
    inner() 
    print("-------" * 3) 
    return (g_var, l_var) 

print(test()) 
exec("print(g_var)") 

Ausgang:

{'l_var': 10} 
{'l_var': 10} 
# locals are the same 
{'l_var': 10, 'g_var': 222} 
# after adding g_var and changing the l_var it only adds g_var and left the l_var unchanged 
{'l_var': 111, 'g_var': 222} 
# l_var is changed because we are changing and printing the locals in one instantiation (one call to exec) 
{'l_var': 10, 'g_var': 222} 
{'l_var': 10, 'g_var': 222} 
# In both function's locals and exec's local l_var is unchanged and g_var is added 
Inner function: 
{} 
{'inner_var': 100} 
{'inner_var': 100} 
# inner_function's local is same as exec's local 
['g_var', 'test'] 
# global is only contain g_var and function name (after excluding the special methods) 
--------------------- 

(5, 10) 
5