Кажется, что закрытие функции python имеет проблемы, если присваивается обозначенный символ:
def outer():
p = []
def gen():
def touch(e):
if e[0] == 'add':
p.append(e);
elif e[0] == 'rem':
p = [ x for x in p if not (x[1] == e[1]) ]
return touch
f = gen()
for i in [["add","test1"],["add","test2"],["rem","test2"],["rem","test1"]]:
f(i)
outer();
и результат:
Traceback (most recent call last):
File "b.py", line 22, in <module>
outer();
File "b.py", line 20, in outer
f(i)
File "b.py", line 14, in touch
p.append(e);
UnboundLocalError: local variable 'p' referenced before assignment
Если я просто для теста заменим:
- p = [ x for x in p if not (x[1] == e[1]logig is) ]
+ a = [ x for x in p if not (x[1] == e[1]) ]
ошибка исчезает, однако код не то, что я хочу. Является ли вышеуказанное поведение ожидаемым с закрытием/вложенными функциями python? Нужно ли обертывать массив для изменения внутри объекта и просто вызвать функции?
С другой стороны, это работает:
class o():
def __init__(self):
self.p = []
def add(self,e):
self.p.append(e);
def rem(self,e):
self.p = [ x for x in self.p if not (x[1] == e[1]) ]
def outer():
p = o()
def gen():
def touch(e):
if e[0] == 'add':
p.add(e);
elif e[0] == 'rem':
p.rem(e)
return touch
f = gen()
for i in [["add","test1"],["add","test2"],["rem","test2"],["rem","test1"]]:
f(i)
outer();
Поскольку вы назначаете p
внутри touch
, он становится локальной переменной в touch
и эффективно "скрывает" все другие имена p
в охватывающих областях. Чтобы сообщить Python, что вы действительно хотите ссылаться на p
внутри outer
, вы должны использовать nonlocal p
, например:
def outer():
p = []
def touch(e):
# The following line is required to refer to outer p
nonlocal p
if e[0] == 'add':
p.append(e)
elif e[0] == 'rem':
p = [ x for x in p if not (x[1] == e[1]) ]
for i in [["add","test1"],["add","test2"],["rem","test2"],["rem","test1"]]:
touch(i)
outer()
Второй пример работает, потому что вы ссылаетесь на атрибут p
в обоих случаях touch
, а не на назначение (p =...
).
См. nonlocal
в справочной документации Python, справочную документацию для областей и PEP 3104, в которой был предложен nonlocal
синтаксис. nonlocal
существует только в Python 3, но есть обходное решение, если необходимо использовать Python 2.