Вложенные области Python с динамическими функциями
Нужна помощь в понимании следующего предложения из PEP 227 и справочника по языку Python
Если указана переменная в закрытой области, это ошибка удалите имя. Компилятор поднимет SyntaxError для 'del имя".
Отсутствие примеров приводило к тому, что я не мог воспроизвести ошибку во время компиляции, поэтому объяснение с примерами очень желательно.
Ответы
Ответ 1
Следующее приводит к выполнению:
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
Ответ 2
Пример может быть следующим:
>>> 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
При включении одного и того же кода в функцию не только изменяется исключение, но и ошибка во время компиляции.