Ответ 1
Python предполагает, что все переменные в функции являются локальными. Это делается для того, чтобы избежать случайного использования глобальной переменной с тем же именем или в охватывающей области. Важным образом это различие связано с тем, что локальное объявление переменной Python является автоматическим/неявным, а в JavaScript - нет (вы должны использовать var
). Решения:
Используйте объявление global
def generateNextNumber(startNumber):
global current
current= startNumber
def tempFunction():
global current
current += 1
return current
return tempFunction
Действителен в некоторых случаях, но в вашем случае может быть активен только один экземпляр tempFunction
.
Использовать атрибут функции
def generateNextNumber(startNumber):
def tempFunction():
tempFunction.current += 1
return tempFunction.current
tempFunction.current= startNumber
return tempFunction
Используется тот факт, что функции являются объектами (и, следовательно, могут иметь атрибуты), что они создаются при их объявлении и становятся локальными для закрывающей функции (или модуля, и в этом случае они действительно глобальны). Это также работает, потому что имя tempFunction
используется впервые в своем собственном определении с помощью оператора "член доступа" .
и, следовательно, не считается локальным. Что-то подобное происходит с операторами "call" ()
и "element access" []
. В следующем случае объясняется, почему ваш код работает.
Привяжите имя к нелокальному
def generateNextNumber(startNumber):
current= type("OnTheFly",(),{})()
current.value= startNumber
def tempFunction():
current.value += 1
return current.value
return tempFunction
Об этом уже говорилось в предыдущем разделе. Используя оператор доступа элемента .
, мы говорим: "current
уже существует", и поэтому он искал в охватывающей области. В этом конкретном случае мы создаем класс с использованием функции type
и сразу создаем его экземпляр (со вторым набором скобок). Вместо общего объекта мы могли бы также использовать список или словарь. Второй случай был очень распространенным решением.
Использовать объект функции
def generateNextNumber(startNumber):
class TempFunction:
def __call__(self):
self.current += 1
return self.current
tempFunction= TempFunction()
tempFunction.current= startNumber
return tempFunction
Любой объект, класс которого имеет метод вызов , является функцией и, следовательно, может быть вызван с помощью оператора функции ()
. Это чрезвычайно связано с двумя предыдущими случаями.
Используйте объявление nonlocal
def generateNextNumber(startNumber):
current= startNumber
def tempFunction():
nonlocal current
current += 1
return current
return tempFunction
Точно так же, как global
означает... ну, глобальный, nonlocal
означает "в предыдущей области". Действителен в Python 3 и, возможно, более поздних версиях Python 2.
Использовать генераторы
def generateNextNumber(current):
while True :
current+= 1
yield current
Это, пожалуй, самый "питонический" способ приблизиться не к общей проблеме нелокального доступа к переменной, а к конкретному случаю, который вы использовали для объяснения. Я не мог закончить, не упомянув об этом. Вы должны называть его незначительными изменениями:
getNextNumber = generateNextNumber(10)
for i in range(10):
print (getNextNumber.next())
При вождении for
вызов next()
является неявным (но генератор не может быть бесконечным, как в моем примере).