UnboundLocalError в Python

Что я здесь делаю неправильно?

counter = 0

def increment():
  counter += 1

increment()

Вышеуказанный код выдает a UnboundLocalError.

112
13 февр. '12 в 20:11
источник поделиться
8 ответов

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

counter += 1

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

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

119
13 февр. '12 в 20:15
источник

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

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'
62
13 февр. '12 в 20:13
источник

Чтобы ответить на вопрос в строке темы *, да, в 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.

13
13 февр. '12 в 20:21
источник

Причина того, почему ваш код вызывает 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)
6
13 февр. '12 в 20:31
источник

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

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

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

>>> x = 1

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

>>> f()
1
3
13 февр. '12 в 20:21
источник

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

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

global counter

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

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

3
13 февр. '12 в 20:13
источник

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

counter = 0

def increment():
  global counter
  counter += 1

increment()
2
13 февр. '12 в 20:14
источник

Посмотрите другие вопросы по меткам или Задайте вопрос