jwd*_*jwd 19 python closures generator
这一点Python不起作用:
def make_incrementer(start):
def closure():
# I know I could write 'x = start' and use x - that's not my point though (:
while True:
yield start
start += 1
return closure
x = make_incrementer(100)
iter = x()
print iter.next() # Exception: UnboundLocalError: local variable 'start' referenced before assignment
Run Code Online (Sandbox Code Playgroud)
我知道如何解决这个错误,但请耐心等待:
这段代码工作正常:
def test(start):
def closure():
return start
return closure
x = test(999)
print x() # prints 999
Run Code Online (Sandbox Code Playgroud)
为什么我可以读取start闭包内的变量而不是写入它?导致这种start变量处理的语言规则是什么?
更新:我发现这个SO帖子相关(答案不仅仅是问题):读/写Python闭包
And*_*ark 32
无论何时在函数内部分配变量,它都将是该函数的局部变量.该行start += 1正在分配一个新值start,因此start是一个局部变量.由于start存在局部变量start,因此当您第一次尝试访问它时,该函数将不会尝试查看全局范围,因此您会看到错误.
在3.x中,如果使用nonlocal关键字,您的代码示例将起作用:
def make_incrementer(start):
def closure():
nonlocal start
while True:
yield start
start += 1
return closure
Run Code Online (Sandbox Code Playgroud)
在2.x上,您通常可以通过使用global关键字解决类似问题,但这不起作用,因为start它不是全局变量.
在这种情况下,您可以执行类似于建议(x = start)的操作,或者使用可修改的变量来修改并生成内部值.
def make_incrementer(start):
start = [start]
def closure():
while True:
yield start[0]
start[0] += 1
return closure
Run Code Online (Sandbox Code Playgroud)
agf*_*agf 10
在Python 2.x上有两个"更好"/更多Pythonic方法,而不是使用容器来解决缺少非本地关键字的问题.
您在代码中的注释中提到的一个 - 绑定到局部变量.还有另一种方法:
def make_incrementer(start):
def closure(start = start):
while True:
yield start
start += 1
return closure
x = make_incrementer(100)
iter = x()
print iter.next()
Run Code Online (Sandbox Code Playgroud)
这具有局部变量的所有好处,而无需额外的代码行.它也发生在x = make_incrememter(100)线路而不是iter = x()线路上,根据情况可能或可能不重要.
您还可以使用"不实际分配给引用变量"方法,以比使用容器更优雅的方式:
def make_incrementer(start):
def closure():
# You can still do x = closure.start if you want to rebind to local scope
while True:
yield closure.start
closure.start += 1
closure.start = start
return closure
x = make_incrementer(100)
iter = x()
print iter.next()
Run Code Online (Sandbox Code Playgroud)
这适用于所有最新版本的Python,并利用这样的事实:在这种情况下,您已经拥有一个对象,您知道您可以引用属性的名称 - 不需要为此目的创建新容器.