Невозможно изменить глобальные переменные в функции с помощью инструкции exec()?

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

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

Ответы

Ответ 1

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

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

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

... и вы сможете использовать глобальные переменные для вашего сердечного содержимого.

Ответ 2

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

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

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

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

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

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

Ответ 3

Как насчет этого:

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

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

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