UnboundLocalError:在python闭包中赋值之前引用的本地变量


我在Python中实现了两个简单的闭包。对我来说,它们看起来是一样的,但一个有效,另一个无效。

工作的是:

def makeInc(x, y):
def inc():
return y + x
return inc
inc5 = makeInc(5, 10)
inc10 = makeInc(10, 5)
inc5 () # returns 15
inc10() # returns 15

但第二个不起作用:

import os
def linker(dest, filename):
print filename
def link(): 
if os.path.isfile(filename): # line 17
filename = os.path.join(os.getcwd(), filename)
dest = os.path.join(dest, filename)
y = rawinput('[y]/n: ln -sf %s %s' % (dest, filename))
if y == 'n':
return 1
else:
return os.system('ln -sf %s %s' %(dest, filename))
else:
return -1
return link
l = linker('~', '.vimrc')
l()  # line 30

执行l():时,在link()的第一行发生故障

Traceback (most recent call last):
File "test.py", line 30, in <module>
l()
File "test.py", line 17, in link
if os.path.isfile(filename):
UnboundLocalError: local variable 'filename' referenced before assignment

它们看起来和我一模一样,所以我不明白为什么第二个不起作用。知道吗?

您已经用filename = os.path.join(os.getcwd(), filename)覆盖了变量,如果将filename =更改为filename以外的内容,则不会出现local variable 'filename' referenced before assignment错误。

一旦设置了filename =,就不再引用传入的参数filename,而是引用内部函数范围内的本地filename,在定义该函数之前,您尝试在if中使用该函数。

如果将两行和其他变量更改为,dest也会出现同样的问题

filename_ = os.path.join(os.getcwd(), filename)
dest_ = os.path.join(dest, filename)

您将看到代码运行良好,因为filename现在引用的是参数,而不是内部函数中定义的局部变量。

如果您尝试在第一个函数中重新分配x,并在定义之前尝试访问x,您将看到完全相同的行为:

def makeInc(x, y):
def inc():
print  y + x # will cause referenced before assignment error
x = 5 # now x is local to the inner func, the x from the outer function is overridden
return y + x
return inc

如果打印__closure__属性,您将看到发生了什么:

def makeInc(x, y):
def inc():
return y + x
return inc
inc5 = makeInc(5, 10)
inc10 = makeInc(10, 5)
print(inc5.__closure__)
(<cell at 0x7f180df67e50: int object at 0xef00f8>, <cell at 0x7f180df67fa0: int object at 0xef0080>)

现在重新分配x:

def makeInc(x, y):
def inc():
print  y + x
x= 5
return y + x
return inc
inc5 = makeInc(5, 10)
inc10 = makeInc(10, 5)
print(inc5.__closure__)
(<cell at 0x7fea11889fd8: int object at 0x291e080>,)

在内部函数中重新分配后,不再引用x

所以基本上,你的两个原始函数之间的根本区别是,在一个函数中,你在局部范围内重新分配变量,而在另一个函数则不是。从上面的代码中可以看出,如果在第一个函数中执行类似的操作,结果完全相同。

有一个很好的啧啧在这里的范围LEGB等。

最新更新