2010-01-18 4 views
14

Почему я не могу изменить глобальные переменные изнутри функции, используя exec()? Он отлично работает, когда оператор присваивания находится вне exec(). Вот пример моей проблемы:Невозможно изменить глобальные переменные в функции с помощью инструкции exec()?

 
>>> myvar = 'test' 
>>> def myfunc(): 
...  global myvar 
...  exec('myvar = "changed!"') 
...  print(myvar) 
... 
>>> myfunc() 
test 
>>> print(myvar) 
test 

ответ

22

Per the docs, то exec оператор имеет два необязательных выражения, недобросовестный globals() и locals(), и всегда выполняет изменения (если таковые имеются) в locals() один.

Так, просто быть более явным/конкретным/точным ...:

>>> def myfunc(): 
... exec('myvar="boooh!"', globals()) 
... 
>>> myfunc() 
>>> myvar 
'boooh!' 

... и вы будете иметь возможность затирать глобальные переменные к содержанию вашего сердца.

+0

Отлично! Спасибо, он отлично работает. :) – linkmaster03

3

Как об этом:

>>> myvar = 'test' 
>>> def myfunc(): 
...  exec('globals()["myvar"] = "changed!"') 
...  print(myvar) 
... 
>>> myfunc() 
changed! 
>>> print(myvar) 
changed! 

Он работал для меня в Python 2.6.

EDIT: На самом деле объяснение Алекс Мартелл намного лучше, чем у меня :)

+0

Это сработало для меня (Python 3.4.1, Win 8.1) выше не было ... – bjd2385

4

Чтобы добавить ответ Алекса: хотя, когда вы опускаете местные житель/глобал аргументы они по умолчанию для местных жителей и глобал вызывающего абонента, это всего лишь удобство взлома; он не означает, что они наследуют полный контекст выполнения вызывающего. В частности:

a. вложенные ячейки области недоступны исполняемому коду. Так что это не удается:

def f(): 
    foo= 1 
    def g(): 
     exec('print foo') 
    g() 
f() 

b. global декларации не переносятся в исполняемый код. Таким образом, по умолчанию, как и в вашем примере, записанные переменные помещаются в словарь locals. Тем не менее, вы можете заставить его работать, говоря:

exec('global myvar\nmyvar = "changed!"') 

Вы действительно не хотите делать это, если сможете это сделать. global уже не приятно и exec - это в значительной степени запах кода сам по себе! Вы не хотели бы сочетать их, если бы не было никакой альтернативы.

Смежные вопросы