Что я здесь не так делаю?
counter = 0
def increment():
counter += 1
increment()
Приведенный выше код выдает UnboundLocalError
.
Что я здесь не так делаю?
counter = 0
def increment():
counter += 1
increment()
Приведенный выше код выдает UnboundLocalError
.
Python не имеет объявлений переменных, поэтому он должен определить scope самих переменных. Он делает это по простому правилу: если есть назначение переменной внутри функции, эта переменная считается локальной. [1] Таким образом, линия
counter += 1
неявно делает counter
локальным для increment()
. Однако попытка выполнить эту строку попытается прочитать значение локальной переменной counter
до ее назначения, в результате получится UnboundLocalError
. [2]
Если counter
- глобальная переменная, то поможет global
. Если increment()
- локальная функция, а counter
- локальная переменная, вы можете использовать nonlocal
в Python 3.x.
Вам нужно использовать глобальный оператор , чтобы вы изменяли счетчик глобальных переменных вместо локальной переменной:
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'
Чтобы ответить на вопрос в строке темы, * да, в 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.
Причина того, почему ваш код вызывает 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)
У Python по умолчанию лексическая область видимости, что означает, что хотя закрытая область может получать доступ к значениям в своей охватывающей области, она не может их изменять (если они не объявлены глобальными с помощью global
).
Закрытие связывает значения в окружении среды с именами в локальной среде. Затем локальная среда может использовать связанное значение и даже переназначить это имя на что-то другое, но не может изменить привязку в окружении.
В вашем случае вы пытаетесь рассматривать counter
как локальную переменную, а не связанное значение. Обратите внимание, что этот код, который связывает значение x
, назначенное в окружении, отлично работает:
>>> x = 1
>>> def f():
>>> return x
>>> f()
1
Чтобы изменить глобальную переменную внутри функции, вы должны использовать ключевое слово global.
Если вы попытаетесь сделать это без строки
global counter
внутри определения приращения создается локальная переменная с именем counter, чтобы не допустить сбрасывания переменной счетчика, от которой зависит вся программа.
Обратите внимание, что вам нужно использовать глобальное значение только при изменении переменной; вы можете считывать счетчик с помощью инкремента без необходимости в глобальном заявлении.
попробуйте это
counter = 0
def increment():
global counter
counter += 1
increment()
Python не просто лексически ограничен.
Смотрите: Использование глобальных переменных в функции, отличной от той, которая их создала
и это: http://www.saltycrane.com/blog/2008/01/python-variable-scope-notes/