@DVoropaev
Ставлю + к карме на хабре за ответы на вопросы

Почему так происходит?

>>> a = 0
>>> def f1():
...       a = 1
... 
>>> f1()
>>> a
0
>>> def f2():
...       print(a)
... 
>>> f2()
0
>>> def f3():
...       print(a)
...       a = 3
... 
>>> f3()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f3
UnboundLocalError: local variable 'a' referenced before assignment
>>>

Почему f1(), f2() работают, а f3() нет
  • Вопрос задан
  • 383 просмотра
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Python
Седой и строгий
Лутц - "Изучаем Python", глава 20, страница 596
Как известно, имена, которым выполняется присваивание внутри функции, по умолчанию рассматриваются как локальные – они располагаются в области видимости функции и существуют только во время работы функции. Но я еще не говорил, что локальные переменные определяются статически, во время компиляции программного кода в инструкции def, а не в соответствии с операциями присваивания, производимыми во время выполнения. Эта особенность становится причиной появления самых причудливых сообщений в группе новостей, получаемых от начинающих программистов.
Обычно, если внутри функции имени не присваивается какое-либо значение, поиск его будет производиться в области видимости объемлющего модуля. Но посмотрите, что произойдет, если добавить инструкцию присваивания переменной X после ее использования.
X = 99
>>> def selector():
... print(X) # Переменная еще не существует!
... X = 88 # X классифицируется как локальная переменная
... # То же самое происходит при “import X”, “def X”...
>>> selector()
Traceback (most recent call last):
...текст сообщения об ошибке опущен...
UnboundLocalError: local variable ‘X’ referenced before assignment

Было получено сообщение о том, что переменная не определена, но причина его появления не очевидна. Этот программный код компилируется интерпретатором во время ввода в интерактивной оболочке или во время импорта модуля. Вовремя компиляции Python обнаруживает операцию присваивания переменной X и делает вывод, что X – это локальное имя везде в теле функции. Но во время выполнения функции, из-за того, что к моменту вызова инструкции print операция присваивания еще не производилась, интерпретатор сообщает о том, что имя не определено. Согласно этому правилу использования имен, он говорит, что обращение к локальной переменной X произведено до того, как ей было присвоено значение. Фактически любая операция присваивания внутри функции создает локальное имя. Операция импортирования, =, вложенные инструкции def, вложенные определения классов и так далее – все трактуются именно таким образом. Проблема возникает из-за того, что операция присваивания делает имена локальными для всей функции, а не только для той ее части, которая следует заинструкцией присваивания.

Читать учебники - полезно.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы