我正在尝试编写一个简单的Python程序。它应该返回一个返回连续斐波那契数字的闭包:
def fibGen():
n_1 = 0
n_2 = 0
n = 1
def fib():
if n_1 ==0 and n_2 ==0:
n_1 = 1
return n
else:
n = n_1 + n_2
n_2 = n_1
n_1 = n
return n
return fib
f = fibGen()
for i in range(0,10):
print(f())
我在运行时遇到此错误:
UnboundLocalError: local variable 'n_1' referenced before assignment
编辑:在我的原始帖子中,我没有在n = 1
的定义中包含fibGen
,但它实际上是一个拼写错误。无论如何,我仍会得到同样的错误。
答案 0 :(得分:5)
Python基于绑定行为在编译时确定变量的范围。如果您指定一个名称,或将其用作import
目标(以及其他一些方法),那么您将在范围内绑定该名称。
您绑定n_1
函数中的n_2
和fib()
;两人都被分配到。这使得fib()
中的这两个名称 local ,而Python甚至不会查看周围的范围。
您需要覆盖此行为,并且可以使用nonlocal
statement执行此操作:
def fibGen():
n_1 = 0
n_2 = 0
def fib():
nonlocal n_1, n_2
if n_1 ==0 and n_2 ==0:
n_1 = 1
return n
else:
n = n_1 + n_2
n_2 = n_1
n_1 = n
return n
return fib
nonlocal
告诉编译器显式您不希望它查看绑定行为,而是将名称视为闭包。
接下来,您在n
测试的第一个分支中使用if
,但您尚未在else
分支之外的任何位置定义它。你应该在那里返回1
:
def fibGen():
n_1 = 0
n_2 = 0
def fib():
nonlocal n_1, n_2
if n_1 ==0 and n_2 ==0:
n_1 = 1
return n_1
else:
n = n_1 + n_2
n_2 = n_1
n_1 = n
return n
return fib
最后但并非最不重要的是,您可以使用元组赋值交换两个变量,不需要中介:
def fibGen():
n_1 = 0
n_2 = 0
def fib():
nonlocal n_1, n_2
if n_1 ==0 and n_2 ==0:
n_1 = 1
else:
n_1, n_2 = n_1 + n_2, n_1
return n_1
return fib
答案 1 :(得分:1)
您无法修改封闭变量,n_1,n_2位于enclosing
空间,而不是在函数空间中,这就是为什么您无法改变变量。
使用nonlocal
关键字
def fibGen():
n_1 = 0
n_2 = 0
def fib():
nonlocal n_1, n_2
if n_1 ==0 and n_2 ==0:
n_1 = 1
return n_1 # return `n_1` here not `n`
else:
n = n_1 + n_2
n_2 = n_1
n_1 = n
return n
return fib
f = fibGen()
for i in range(0,10):
print(f())
答案 2 :(得分:0)
我一直在回顾这些众所周知的算法中的一些,并认为我会在 Python 中使用闭包来分享我的斐波那契版本:
#!/usr/bin/env python
def fibonacci():
a = 0
b = 1
def internal_fibonacci():
nonlocal a, b
a, b = b, a+b
return a
return internal_fibonacci
def main():
f = fibonacci()
for i in range(0,10):
print("f(" + str(i) + ") => " + str(f()))
if __name__ == '__main__':
main()
比这里提供的其他解决方案更优雅。