外部函数中的嵌套函数更改变量不起作用

时间:2016-12-22 08:32:45

标签: python python-3.x nested python-nonlocal

def some_func(a): 
    def access_a():
        print(a)
    access_a()

输出a的值。但是,如果我想在嵌套函数中更改a,请执行以下操作:

def some_func(a): 
    def change_a():
        a += 1
        print(a)
    change_a()

它引发UnboundLocalError例外。

我知道a是一个非本地变量,但为什么我可以在不声明nonlocal a的情况下访问它?

3 个答案:

答案 0 :(得分:2)

Python范围规则101:

  1. 在函数体中绑定的名称被视为local,除非明确声明global(Python 2.x和3.x)或nonlocal(仅限Python 3.x) )。无论赋值发生在函数体内,这都适用。在绑定之前尝试读取局部变量当然是一个错误。

  2. 如果读取了一个名称但未在函数体中绑定,则将在封闭的范围中查找(如果有任何全局范围,则在外部函数中查找)。注意:函数参数是事实上的本地名称,因此它们永远不会被封闭的范围内查找。

  3. 请注意,a += 1主要是a = a + 1的快捷方式,因此在您的示例中a是本地的(绑定在函数体内,而不是明确声明为全局或非本地),但是您尝试在它被束缚之前阅读它(a = a+1的rhs。)

    在Python 3中,您可以使用nonlocal语句解决此问题:

    >>> def outer(a):
    ...    def change():
    ...       nonlocal a
    ...       a += 1
    ...    print("before : {}".format(a))
    ...    change()
    ...    print ("after : {}".format(a))
    ... 
    >>> outer(42)
    before : 42
    after : 43
    

    Python 2没有nonlocal所以规范的hack是将变量包装在一个可变容器中(通常是list,但任何可变对象都可以):

    >>> def outer(a):
    ...     _a = [a]
    ...     def change():
    ...         _a[0] += 1
    ...     print("before : {}".format(_a[0]))
    ...     change()
    ...     print ("after : {}".format(_a[0]))
    ... 
    >>> outer(42)
    before : 42
    after : 43
    
    至少可以说这是非常难看的。

    现在虽然闭包非常方便,但它们大部分都是对象的功能对应物:一种在保留这种状态封装的同时在一组函数之间共享状态的方法,所以如果你发现需要一个{{1}变量也许一个合适的类可能是一个更清晰的解决方案(虽然可能不是你的例子不返回内部函数但只在内部使用它)。

答案 1 :(得分:1)

我有两个解决方案:

#first one:
# try with list, compound data types dict/list
def some_func(a): 
    def change_a():
        a[0] += 1
        print(a[0])
    change_a()
some_func([1])
>>> 2


#second one
#reference pointer 
from ctypes import *
def some_func_ctypes(a):
    def change_a():
      a[0] += 1
      print a.contents, a[0]
    change_a()

i = c_int(1)
pi = pointer(i)
some_func_ctypes(pi)

>>> c_int(2) 2

答案 2 :(得分:0)

使用a运算符时,会为http = require('http'); server = http.createServer(); Primus = require('primus'); primus = new Primus(server, { transformer: 'websockets', pathname: 'ws' }); primus.on('connection', function connection(spark) { console.log("client has connected"); spark.write("Herro Client, I am Server"); spark.on('data', function(data) { console.log('PRINTED FROM SERVER:', data); spark.write('receive '+data) }); spark.on('error', function(data) { console.log('PRINTED FROM SERVER:', data); spark.write('receive '+data) }); }); server.listen(5431); console.log("Server has started listening"); 分配一个新值。这使得翻译者眼中的本地化。