Не понимаю, почему происходит UnboundLocalError

Что я здесь не так делаю?

counter = 0

def increment():
  counter += 1

increment()

Приведенный выше код выдает UnboundLocalError.

Ответ 1

Python не имеет объявлений переменных, поэтому он должен определить scope самих переменных. Он делает это по простому правилу: если есть назначение переменной внутри функции, эта переменная считается локальной. [1] Таким образом, линия

counter += 1

неявно делает counter локальным для increment(). Однако попытка выполнить эту строку попытается прочитать значение локальной переменной counter до ее назначения, в результате получится UnboundLocalError. [2]

Если counter - глобальная переменная, то поможет global. Если increment() - локальная функция, а counter - локальная переменная, вы можете использовать nonlocal в Python 3.x.

Ответ 2

Вам нужно использовать глобальный оператор , чтобы вы изменяли счетчик глобальных переменных вместо локальной переменной:

counter = 0

def increment():
  global counter
  counter += 1

increment()

Если область охвата, в которой counter определена, не является глобальной областью, на Python 3.x вы можете использовать нелокальное утверждение. В той же ситуации на Python 2.x у вас не будет возможности переназначить нелокальное имя counter, поэтому вам нужно будет изменить counter и изменить его:

counter = [0]

def increment():
  counter[0] += 1

increment()
print counter[0]  # prints '1'

Ответ 3

Чтобы ответить на вопрос в строке темы, * да, в Python есть замыкания, за исключением того, что они применяются только внутри функции, а также (в Python 2.x) они доступны только для чтения; Вы не можете повторно привязать имя к другому объекту (хотя, если объект изменчив, вы можете изменить его содержимое). В Python 3.x вы можете использовать ключевое слово nonlocal, чтобы изменить переменную замыкания.

def incrementer():
    counter = 0
    def increment():
        nonlocal counter
        counter += 1
        return counter
    return increment

increment = incrementer()

increment()   # 1
increment()   # 2

* Первоначально задавался вопрос о замыканиях в Python.

Ответ 4

Причина того, почему ваш код вызывает UnboundLocalError, уже хорошо объясняется в других ответах.

Но мне кажется, что вы пытаетесь создать что-то, что работает как itertools.count().

Так почему бы вам не попробовать и посмотреть, подходит ли это вашему делу:

>>> from itertools import count
>>> counter = count(0)
>>> counter
count(0)
>>> next(counter)
0
>>> counter
count(1)
>>> next(counter)
1
>>> counter
count(2)

Ответ 5

У Python по умолчанию лексическая область видимости, что означает, что хотя закрытая область может получать доступ к значениям в своей охватывающей области, она не может их изменять (если они не объявлены глобальными с помощью global).

Закрытие связывает значения в окружении среды с именами в локальной среде. Затем локальная среда может использовать связанное значение и даже переназначить это имя на что-то другое, но не может изменить привязку в окружении.

В вашем случае вы пытаетесь рассматривать counter как локальную переменную, а не связанное значение. Обратите внимание, что этот код, который связывает значение x, назначенное в окружении, отлично работает:

>>> x = 1

>>> def f():
>>>  return x

>>> f()
1

Ответ 6

Чтобы изменить глобальную переменную внутри функции, вы должны использовать ключевое слово global.

Если вы попытаетесь сделать это без строки

global counter

внутри определения приращения создается локальная переменная с именем counter, чтобы не допустить сбрасывания переменной счетчика, от которой зависит вся программа.

Обратите внимание, что вам нужно использовать глобальное значение только при изменении переменной; вы можете считывать счетчик с помощью инкремента без необходимости в глобальном заявлении.

Ответ 7

попробуйте это

counter = 0

def increment():
  global counter
  counter += 1

increment()