从父函数赋值给变量:"赋值前引用的局部变量"

crk*_*crk 32 python

对于以下Python 2.7代码:

#!/usr/bin/python

def funcA():
   print "funcA"
   c = 0 
   def funcB():
      c += 3
      print "funcB", c

   def funcC():
      print "funcC", c

   print "c", c
   funcB()
   c += 2
   funcC()
   c += 2
   funcB()
   c += 2
   funcC()
   print "end"

funcA()
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

File "./a.py", line 9, in funcB
    c += 3
UnboundLocalError: local variable 'c' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

但是,当我注释掉该行c += 3funcB,我得到以下的输出:

funcA
c 0
funcB 0
funcC 2
funcB 4
funcC 6
end
Run Code Online (Sandbox Code Playgroud)

c+=in funcB=in 两种情况下都没有访问funcC?为什么不为一个而不是另一个抛出错误?

我没有做一个选择c一个全局变量,然后宣布global cfuncB.无论如何,关键不是要c增加,funcB而是为什么它会抛出错误,funcB而不是因为funcC它们都在访问本地或全局的变量.

And*_*ark 63

您在这里看到的是访问和分配变量之间的区别.在Python 2.x中,您只能分配最内层范围或全局范围内的变量(后者通过使用全局语句完成).您可以访问任何封闭范围中的变量,但不能访问封闭范围中的变量,然后在最内层或全局范围内分配变量.

这意味着如果对函数内部的名称进行了任何赋值,则在访问名称之前必须已在最内层作用域中定义该名称(除非使用了全局语句).在您的代码中,该行c += 3基本上等同于以下内容:

tmp = c
c = tmp + 3
Run Code Online (Sandbox Code Playgroud)

因为c函数中有赋值,所以该函数中的每个其他实例c都只会查找本地范围funcB.这就是为什么你看到错误,你试图c获取它的当前值+=,但是在本地范围内c还没有定义.

在Python 3中,您可以通过使用非本地语句来解决此问题,该语句允许您分配不在当前范围内但不在全局范围内的变量.

你的代码看起来像这样,在顶部有一个类似的行funcC:

   def funcB():
      nonlocal c
      c += 3
      ...
Run Code Online (Sandbox Code Playgroud)

在Python 2.x中,这不是一个选项,唯一可以更改非局部变量值的方法是它是否可变.

最简单的方法是将值包装在一个列表中,然后在之前刚使用过变量名的每个位置修改和访问该列表的第一个元素:

def funcA():
   print "funcA"
   c = [0]
   def funcB():
      c[0] += 3
      print "funcB", c[0]

   def funcC():
      c[0] = 5
      print "funcC", c[0]

   print "c", c[0]
   funcB()
   funcC()
   funcB()
   funcC()
   print "end"

funcA()
Run Code Online (Sandbox Code Playgroud)

......和输出:

funcA
c 0
funcB 3
funcC 5
funcB 8
funcC 5
end
Run Code Online (Sandbox Code Playgroud)

  • 多好的解释!这个Python的一个黑暗的角落,只是**在一个函数中的任何地方****的任务**的存在**(在我的情况下更接近末尾)只是让我疯狂,当我拼命搜索其他SO答案中的解释以及外部互联网.当我遇到一些反例而不是**产生该死的错误时,开得更加疯狂,解释访问全局变量在Python中都可以!最后,在这里开悟了!^ _ ^ (4认同)

Fre*_*Foo 6

在funcB中的'+ ='和funcC中的'='都不能访问'c'吗?

不,funcC制作一个新变量,也称为c.=在这方面是不同的+=.

要获得您(可能)想要的行为,请将变量包装在单个元素列表中:

def outer():
    c = [0]
    def inner():
        c[0] = 3
    inner()
    print c[0]
Run Code Online (Sandbox Code Playgroud)

将打印3.

编辑:你想要c作为一个参数传递.Python 2没有其他方法,AFAIK,以获得所需的行为.Python 3 nonlocal为这些案例引入了关键字.