问题
I am trying to understand Python 3 variable scoping and nonlocal
.
Consider the following function (it is just an example):
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
This works fine without nonlocal
. But if now I want to conditionally create getters and setters depending on something
I need nonlocal.
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
Why is nonlocal
needed in one case, but not in the other? In other word, why something
if correctly found in the first case (without nonlocal
), but in the second I get: "UnboundLocalError: local variable 'something' referenced before assignment" if nonlocal
is not present?
回答1:
First: nonlocal
is not necessary in the code you've written. You're not changing the object that something
points to.
Second: There are cases where you would need to use nonlocal
. Below is some code where nonlocal
is necessary. Note that all of the assertions are correct (That is, they do not raise an 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()
Third: The code you've presented does not produce the error that you claim it does. If I remove the nonlocal
line, and call the following functions, I get no errors.
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
I'm sorry, I deserve the flame. Above code I wrote up quickly, makes the answer that was previously here a bunch of nonsense.
But it's surprising. I always thought of python(2.x) as a completely foresight-less language, evaluating everything at the last moment...
Sorry for what now is off-topic.
来源:https://stackoverflow.com/questions/21063221/understanding-nonlocal-in-python-3