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

Переменные, объявленные вне функции

Возможный дубликат:
ссылка перед ошибкой присваивания в 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 не удалось?

4b9b3361

Ответ 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