Python вложенные области с динамическими функциями
Нужна помощь в понимании следующего предложения из PEP 227 и Python Language Reference
Если на переменную ссылаются в закрытой области видимости, удаление имени является ошибкой. Компилятор вызовет SyntaxError для "del name".
Отсутствие примеров привело к тому, что я не смог воспроизвести ошибку во время компиляции, поэтому объяснение с примерами крайне желательно.
2 ответа
Следующее поднимает исключение:
def foo():
spam = 'eggs'
def bar():
print spam
del spam
поскольку spam
переменная используется в закрытой области видимости bar
:
>>> def foo():
... spam = 'eggs'
... def bar():
... print spam
... del spam
...
SyntaxError: can not delete variable 'spam' referenced in nested scope
Python обнаруживает, что spam
упоминается в bar
но ничего не присваивает этой переменной, поэтому он ищет ее в окружающей области видимости foo
, Это назначено там, делая del spam
утверждение синтаксическая ошибка.
Это ограничение было снято в Python 3.2; теперь вы несете ответственность за то, чтобы не удалять вложенные переменные самостоятельно; вы получите ошибку во время выполнения (NameError
) вместо:
>>> def foo():
... spam = 'eggs'
... def bar():
... print(spam)
... del spam
... bar()
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in foo
File "<stdin>", line 4, in bar
NameError: free variable 'spam' referenced before assignment in enclosing scope
Примером может быть этот:
>>> def outer():
... x = 0
... y = (x for i in range(10))
... del x
...
SyntaxError: can not delete variable 'x' referenced in nested scope
По сути, это означает, что вы не можете удалить переменные, которые используются во внутренних блоках (в этом случае genexp).
Обратите внимание, что это применимо для python <= 2.7.x и python < 3.2. В python3.2 это не вызывает синтаксическую ошибку:
>>> def outer():
... x = 0
... y = (x for i in range(10))
... del x
...
>>>
Смотрите эту ссылку для всей истории изменений.
Я думаю, что семантика python3.2 более правильная, потому что если вы пишете тот же код вне функции, она работает:
#python2.7
>>> x = 0
>>> y = (x for i in range(10))
>>> del x
>>> y.next() #this is what I'd expect: NameError at Runtime
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
NameError: global name 'x' is not defined
При помещении одного и того же кода в функцию изменяется не только исключение, но и ошибка во время компиляции.