了解 Python 3 中的非本地
Posted
技术标签:
【中文标题】了解 Python 3 中的非本地【英文标题】:Understanding nonlocal in Python 3 【发布时间】:2014-01-30 13:00:35 【问题描述】:我正在尝试了解 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
有条件地创建 getter 和 setter,我需要非本地的。
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: local variable 'something' referenced before assignment”如果nonlocal
不存在?
【问题讨论】:
...你的问题是?你确实没有说任何关于错误/意外行为的事情。如果您遇到异常,请在您的问题中提供 full 回溯。如果您看到意外的行为,您应该提供 1) 您期望的行为和 2) 您获得的实际输出。我们不是算命的。 只是出于好奇:你的装饰器有什么意义?你似乎没有在任何地方使用func
...
顺便说一句,我没有测试代码,但我不明白为什么在第二种情况下需要它,因为something
从未分配给...
在这种情况下需要nonlocal
是不正确的。仅当您分配给something
时才需要nonlocal
。
【参考方案1】:
首先: 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)
【讨论】:
【参考方案2】: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) 是一种完全没有远见的语言,在最后一刻评估一切......
抱歉现在跑题了。
【讨论】:
我写了一些愚蠢的东西,但它是关于保留父作用域的引用,是的。 这个答案不正确。nonlocal
不是优化,需要正确识别要创建变量的范围。 Python 2 不会保留所有封闭的局部变量,只保留那些被闭包引用的局部变量 - 与 Python 3 完全一样。不同之处在于 Python 3 允许您更改封闭变量的值没有创建新变量作为副作用。 nonlocal
告诉编译器,尽管赋值发生在内部块中,但被修改的变量是在外部块中创建的变量。以上是关于了解 Python 3 中的非本地的主要内容,如果未能解决你的问题,请参考以下文章