Понимание нелокальности в Python 3
Я пытаюсь понять область видимости переменных Python 3 и nonlocal
,
Рассмотрим следующую функцию (это всего лишь пример):
def build_property(something):
def deco(func):
def getter(self):
return getattr(self, something)
def setter(self, value):
setattr(self, something, value)
return property(getter, setter)
return deco
Это прекрасно работает без nonlocal
, Но если сейчас я хочу условно создавать геттеры и сеттеры в зависимости от something
Мне нужен нелокальный.
def build_property(something):
def deco(func):
nonlocal something # This is needed
if something.startswith('A'):
getter = None
else:
def getter(self):
return getattr(self, something)
if something.startswith('B'):
setter = None
else:
def setter(self, value):
setattr(self, something, value)
return property(getter, setter)
return deco
Почему nonlocal
нужен в одном случае, а не в другом? Другими словами, почему something
если правильно найдено в первом случае (без nonlocal
), но во втором я получаю: "UnboundLocalError: локальная переменная" что-то ", на которое ссылаются до назначения", если nonlocal
нету?
2 ответа
Первый: nonlocal
не обязательно в написанном вами коде. Вы не меняете объект, который something
указывает на.
Второе: есть случаи, когда вам нужно будет использовать nonlocal
, Ниже приведен код где nonlocal
является необходимым. Обратите внимание, что все утверждения верны (то есть они не вызывают ошибку AssertionError).
def main():
variable = 1
def function():
variable = 2
function()
assert variable == 1
def function():
nonlocal variable
variable = 2
function()
assert variable == 2
if __name__ == '__main__':
main()
Третье: код, который вы представили, не выдает ошибку, о которой вы заявляете. Если я удалю nonlocal
линии, и вызовите следующие функции, я не получаю ошибок.
build_property('A')(lambda: True)
build_property('B')(lambda: True)
build_property('C')(lambda: True)
def A(d):
outer = object()
d["outer"] = outer
def B():
print locals()
assert d["outer"] is outer #This fails and never reaches
inner = object()
d=dict() #this line.
print locals()
def C():
print locals()
assert d["outer"] is outer #This goes on fine.
inner = object()
print locals()
return B,C
=> b,c = A(dict())
=> c()
-snip, AOK-
=> b()
UnboundLocalError: local variable 'd' referenced before assignment
Извини, я заслуживаю пламени. Выше код, который я написал быстро, делает ответ, который ранее был здесь кучей глупостей.
Но это удивительно. Я всегда думал о Python(2.x) как о языке без предвидения, оценивая все в последний момент...
Извините за то, что сейчас не по теме.