Переменные, объявленные вне функции
Возможный дубликат:
ссылка перед ошибкой присваивания в python
локальная переменная, указанная перед назначением
Хорошо, я просто пытался выяснить, как работают области видимости переменных и работает в следующей ситуации. Все запущенные терминалы:
x = 1
def inc():
x += 5
inc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in inc
UnboundLocalError: local variable 'x' referenced before assignment
Итак, я хорошо подумал, может быть, у меня нет доступа к x в моем методе, поэтому я попробовал:
def inc():
print x
1
Итак, это работает. Теперь я знаю, что могу просто сделать:
def inc():
global x
x += 1
И это сработает. Но мой вопрос: почему первый пример терпит неудачу. Я хотел бы ожидать, что, поскольку print x
работал, что x виден внутри функции, так почему бы x + = 5 не удалось?
Ответы
Ответ 1
В отличие от языков, которые используют "истинное" лексическое охват, Python предпочитает иметь конкретные "пространства имен" для переменных, будь то global
, nonlocal
или local. Можно утверждать, что разработчики сознательно кодируют такие пространства имен в более ясном, более понятном. Я бы сказал, что такие сложности делают язык более громоздким, но я предполагаю, что все это зависит от личных предпочтений.
Вот несколько примеров относительно global
: -
>>> global_var = 5
>>> def fn():
... print(global_var)
...
>>> fn()
5
>>> def fn_2():
... global_var += 2
... print(global_var)
...
>>> fn_2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn_2
UnboundLocalError: local variable 'global_var' referenced before assignment
>>> def fn_3():
... global global_var
... global_var += 2
... print(global_var)
...
>>> fn_3()
7
Те же шаблоны могут применяться и к переменным nonlocal
, но это ключевое слово доступно только для последних версий Python.
Если вам интересно, nonlocal
используется там, где переменная не является глобальной, но не входит в определение функции, которое используется. Например, a def
в пределах def
, что является обычным явлением, частично из-за отсутствия многопроцессорных lambdas. Там хак, чтобы обойти недостаток этой функции в ранних Pythons, хотя я смутно помню, что это связано с использованием списка из одного элемента...
Обратите внимание, что запись в переменные - это то, где эти ключевые слова необходимы. Просто чтение из них не является двусмысленным, поэтому не нужно. Если у вас нет внутреннего def
, используя те же имена переменных, что и внешние, чего просто следует избегать, чтобы быть честным.
Ответ 2
Когда Python анализирует функцию, она замечает, когда выполняется переменная присваивание. Когда есть назначение, по умолчанию предполагается, что эта переменная является локальной переменной. Чтобы объявить, что присвоение относится к глобальной переменной, вы должны использовать объявление global
.
Когда вы получаете доступ к переменной в функции, ее значение просматривается с помощью правил LEGB scoping.
Итак, первый пример
x = 1
def inc():
x += 5
inc()
создает UnboundLocalError
, потому что Python определяет x
внутри inc
как локальную переменную,
при доступе к x
работает во втором примере
def inc():
print x
потому что здесь, в соответствии с правилом LEGB, Python ищет x
в локальной области, не находит его, затем ищет его в расширенной области, все еще не находит и, наконец, ищет его в глобальный охват успешно.
Ответ 3
Локальное пространство имен для функции создается при вызове функции. В вашем первом случае (с x += 5
i.e. x = x + 5
), x существует в локальном пространстве имен. Но во втором случае x не существует в локальном пространстве имен, поэтому он просматривается в глобальном пространстве имен.
Подобный вопрос в faq: http://docs.python.org/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value