UnboundLocalError:在python闭包中赋值之前引用的局部变量 [英] UnboundLocalError: local variable referenced before assignment in python closure

查看:781
本文介绍了UnboundLocalError:在python闭包中赋值之前引用的局部变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Python中实现了两个简单的闭包。对我来说,他们看起来是一样的,但一个工作,另一个不工作。



工作的是:

  def makeInc(x,y):
def inc():
return y + x
return inc
$ b b inc5 = makeInc(5,10)
inc10 = makeInc(10,5)

inc5()#返回15
inc10()#返回15

但第二个不起作用:

  import os 
def linker(dest,filename):
打印文件名
def link():
如果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))
如果y =='n':
return 1
else:
return os.system ('ln -sf%s%s'%(dest,filename))
else:
return -1
返回链接

l = linker ,'.vimrc')
l()#line 30

执行 l()时: link()

 跟踪(最近一次调用):
文件test.py,第30行,在< module>
l()
文件test.py,第17行,在链接
如果os.path.isfile(filename):
UnboundLocalError:局部变量'filename'

他们看起来和我一样,所以我不明白为什么第二个不工作。任何想法?

解决方案

您已经覆盖变量 filename = os.path.join如果将 filename = 更改为除 filename >



一旦你设置了,你就不会得到局部变量'filename' c $ c> filename = 你不再指的是你传递的参数 filename 指的是本地 filename 在您尝试在if before 之前定义的内部函数的作用域中。



如果您将两行和其他变量更改为以下类型,您将会遇到与dest相同的问题:

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

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

如果您尝试在第一个函数中重新分配 x ,并尝试访问 x 之前定义它:

  def makeInc(x,y):
def inc():
print y + x#将导致赋值之前引用错误
x = 5#现在x是内部函数的局部变量,外部函数的x被覆盖
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在0x7f180df67e50:int object at 0xef00f8>,< cell on 0x7f180df67fa0:int object at 0xef0080>)
pre>

现在重新分配x:

  def makeInc ):
def inc():
print y + x
x = 5
return y + x
return inc

inc5 = makeInc (5,10)
inc10 = makeInc(10,5)
print(inc5 .__ closure__)
(< cell 0x7fea11889fd8:int object at 0x291e080> ;,)

在内部函数中重新赋值后,不再引用 x



所以基本上你的两个原始函数的根本区别是,在一个你重新分配的变量在本地范围,而在其他你不是。从上面的代码可以看出,如果你在第一个函数中做类似的事情,结果是完全一样的。



有一个不错的选择此处范围LEGB等。


I implemented two simple closures in Python. To me, they looks the same, but one works and the other doesn't.

The working one is:

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

But the second one doesn't work:

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

It faults at the first line of link() when executing l():

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

They seem identical to me so I don't understand why the second one doesn't work. Any idea?

解决方案

You have overwritten the variable with filename = os.path.join(os.getcwd(), filename), if you change the filename = to something other than filename you won't get a local variable 'filename' referenced before assignment error.

Once you set filename = you are no longer referring to the parameter filename that is passed in you are referring to the local filename in the scope of the inner function which you try to use in the if before you have it defined.

You will have the same problem with dest, if you change the two lines and the other variables to something like:

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

You will see the code runs fine as filename now refers to the parameter not to a local variable defined in your inner function.

You will see the exact same behaviour if you try to reassign x in your first function and try to access x before you have defined it:

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

If you print the __closure__ attribute you will see what happens:

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>)

Now reassigning 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>,)

After reassigning in the inner function, there is no longer a reference to x.

So basically the fundamental difference between your two original functions is that in one you are reassigning the variable in the local scope and in the other you are not. As you can see from the code above if you do something similar in the first function the outcome is exactly the same.

There is a nice tut here on scopes LEGB etc..

这篇关于UnboundLocalError:在python闭包中赋值之前引用的局部变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆