Подтвердить что ты не робот

Почему exec не работает в функции с подфункцией?

Похоже, вы не можете использовать exec в функции, которая имеет подфункцию...

Кто-нибудь знает, почему этот код Python не работает? Я получаю сообщение об ошибке в exec в test2. Кроме того, я знаю, что exec не очень хороший стиль, но поверьте мне, я использую exec для соответствующей причины. Я бы не использовал его в противном случае.

#!/usr/bin/env python
#

def test1():
    exec('print "hi from test1"')

test1()

def test2():
    """Test with a subfunction."""
    exec('print "hi from test2"')
    def subfunction():
        return True

test2()

EDIT: я сузил ошибку до функции в подфункции. Это не имеет никакого отношения к ключевому слову raise.

4b9b3361

Ответ 1

Правильно. Вы не можете использовать exec в функции, которая имеет подфункцию, если вы не указали контекст. Из документов:

Если exec используется в функции, а функция содержит вложенный блок с свободных переменных, компилятор будет поднимите СинтаксисError, если только exec явно указывает локальные пространство имен для exec. (В других слова "exec obj" были бы незаконными, но "exec obj in ns" будет законным.)

Есть веские причины для этого, которые я, вероятно, пойму, если бы это было не в воскресенье вечером. Теперь, следующий вопрос: почему вы используете exec? Это очень редко необходимо. Вы говорите, что у вас есть веская причина. Я скептически отношусь к этому.;) Если у вас есть веская причина, я скажу вам обходной путь.:-P

Хорошо, вот так или иначе:

def test2():
    """Test with a subfunction."""
    exec 'print "hi from test2"' in globals(), locals()
    def subfunction():
        return True

Ответ 2

Хотя в Python это похоже на то, что локальные переменные хранятся в словаре locals(), они обычно не являются. Вместо этого они в основном хранятся в стеке и доступны по индексу. Это делает поиск локальных переменных быстрее, чем если бы каждый раз приходилось выполнять поиск по словарю. Если вы используете функцию locals(), то вы получаете свежий словарь, созданный из всех локальных переменных, и почему назначение locals() обычно не работает.

Есть несколько исключений из этого сценария:

Когда вы используете неквалифицированный exec внутри функции, Python отключает оптимизацию и использует настоящий словарь для локальных переменных. Это означает, что вы можете создавать или обновлять переменные из exec, но это также означает, что доступ к локальной переменной в этой функции будет выполняться медленнее.

Другое исключение состоит в том, что когда вы вставляете функции, внутренняя функция может обращаться к локальным переменным во внешней области видимости. Когда это происходит, переменная хранится в объекте "cell", а не хранится в стеке. Дополнительный уровень косвенности делает все использование переменных с областью действия медленнее, независимо от того, получаете ли вы их от внутренней или внешней функции.

Ловушка, с которой вы столкнулись, состоит в том, что эти два исключения, как обычно хранятся локальные переменные, несовместимы. Вы не можете иметь переменную, хранящуюся в словаре, и одновременно обращаться к ней через ссылку на ячейку. Python 2.x исправляет это, запрещая exec, даже в таких случаях, когда вы не пытаетесь использовать какие-либо переменные с областью.

Ответ 3

Это хорошо работает в Python 3.1.3 после изменения инструкции печати для использования функции печати. ​​

В Python 2.6 он производит SyntaxError: unqualified exec is not allowed in function 'test2' it contains a nested function with free variables, я не думаю, что это ошибка.

Ответ 4

Это довольно интересный случай:

>>> def func():
...     exec('print "hi from func"')
...     def subfunction():
...         return True
... 
  File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function 'func' because 
it contains a nested function with free variables

Причина, по которой это не работает, заключается в том, что subfunction содержит свободную переменную, и поскольку в Python 2, exec теоретически может модифицировать локали в области содержимого, было бы невозможно решить, будет ли переменная должен быть связан с глобальной или родительской функцией. Один из стихов в "Дзен Питона" - "Перед лицом двусмысленности, откажитесь от соблазна угадать". и это то, что делает Python 2.

Теперь возникает вопрос: что это за несвязанная переменная? Ну, это True!

Действительно, он воспроизводится с помощью None:

>>> def func():
...     exec('print "hi from func"')
...     def subfunction():
...         return None
... 
  File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function 'test2' because it contains a nested
function with free variables

Даже если None не может быть назначен, и он считается константой в байт-коде, багги-парсер считает, что это несвязанная переменная здесь.

Но если вы замените его на 1, и он работает без проблем:

>>> def test2():
...     exec('print "hi from func"')
...     def subfunction():
...         return 1
... 
>>>

Чтобы избежать этой ошибки, укажите явно глобальные и, возможно, локальные, которые будут использоваться exec, скажем:

>>> def test2():
...     exec 'print "hi from test2"' in {}
...     def subfunction():
...         return None
...
>>>

В Python 3, exec является просто простой функцией и не обрабатывается специально парсером или компилятором байт-кода. В Python 3 exec не удается восстановить функции-локальные имена, и, таким образом, этот синтаксисError и двусмысленность не существует.


Одним из особых случаев совместимости Python 2 vs 3 является то, что в то время как Документация Python 2.7 утверждает, что

Форма exec(expr, globals) эквивалентна exec expr in globals, а форма exec(expr, globals, locals) эквивалентна exec expr in globals, locals. Форма кортежа exec обеспечивает совместимость с Python 3, где exec - это функция, а не оператор.

Форма кортежа не всегда была на 100% совместимой, так как была ошибка при обработке exec в функциях с вложенными функциями (номер 21591); вплоть до Python 2.7.8 следующий код может вызвать исключение:

def func():
    exec('print "hi from test2"', {})
    def subfunction():
        return None

Это было исправлено в Python 2.7.9, и он больше не бросает.

Ответ 5

Ошибка кажется мне довольно очевидной:

SyntaxError: unqualified exec is not allowed in function 'test2' it contains a nested function with free variables

Подробнее см. pep 227: http://www.python.org/dev/peps/pep-0227/