cnDenis http://cndenis.github.io 2012-12-26

在Python 2.x中,函数内部可以定义函数,内层的函数可以读取外层函数的局部变量,但却不可以修改它.

    def outter():
        x = 1
        def inner():
            print("inner is called, x=", x)
        return inner

    outter()()

上面这个程序是没问题的,但是,下面这个就会出错:

    def outter():
        x = 1
        def inner():
            print("inner is called, x=", x)
            x = 2
        return inner

    outter()()

提示竟然是UnboundLocalError: local variable 'x' referenced before assignment,找不到变量。

这个错误在Python 3.x中的解决方法是使用Py3k新增的关键词nonlocal

    def outter():
        x = 1
        def inner():
            nonlocal x
            print("inner is called, x=", x)
            x = 2
        return inner

    outter()()

但Python 2.x中没有这个关键词,怎么办呢?如果对变量的改变的不需要影响外层的话,可以新建一个变量来用也可以。

新建变量的方式:

    def outter():
        x = 1
        def inner():
            y = x
            print("inner is called, x=", y)
            y = 2
        return inner

    outter()()

由于y是在内层函数中定义的,可以随便改变,但外层函数看不见y。而如果需要内层对变量的改变被外层看到的话,变通的方法是使用可变的对象,例如dict、对像的属性等。例如 Python 3.x中的代码:

    def outter():
        x = 1
        def inner():
            nonlocal x
            print("inner is called, x=", x)
            x = 2
        inner()
        print("outter after inner called, x=", x)

    outter()

    #Python 3.3中输出:
    #inner is called, x= 1
    #outter after inner called, x= 2

在Python 2.x中用dict的方式变通为:

    def outter():
        x = {}
        x[0] = 1
        def inner():
            print("inner is called, x=", x[0])
            x[0] = 2
        inner()
        print("outter after inner called, x=", x[0])

    outter()
    #Python 2.7中输出:
    #inner is called, x= 1
    #outter after inner called, x= 2

用对像的属性的方式:

    class C(object):
        pass

    def outter():
        x = C()
        x.v = 1
        def inner():
            print("inner is called, x=", x.v)
            x.v = 2
        inner()
        print("outter after inner called, x=", x.v)

    outter()
    #Python 2.7中输出:
    #inner is called, x= 1
    #outter after inner called, x= 2

以上内容参考了:Python的闭包与nonlocal 以及 Simulating nonlocal in Python 2.x



blog comments powered by Disqus
头像

cnDenis

Email: 联系我

Fork me on GitHub