如何改变外部函数变量?

时间:2018-04-11 07:53:55

标签: python-2.7 scope python-nonlocal

在Mark Lutz的“学习Python”中,我读到: “函数可以自由地使用在语法封闭函数和全局范围中分配的名称,但是它们必须声明这样的非局部和全局变量才能更改它们” 我没能在Python 2.7中测试它们

def f1():
    f1_a = 'f1_a'
    def f2():
 #       global f1_a
 #       nonlocal f1_a
        f2_a = 'f2_a'
        print 'f2_a={:s}'.format(f2_a)
        print 'f1_a={:s}'.format(f1_a)
        f1_a = 'f1f2_a'

    f2()
    print 'f1_a={:s}'.format(f1_a)

>>> f1()

给出错误:

UnboundLocalError: local variable 'f1_a' referenced before assignment

'global'(NameError:全局名称'f1_a'未定义)和'nonlocal'(非本地f1_a,SyntaxError:无效语法)不起作用。这是否意味着没有办法改变外部函数中引入的变量从内部(直接封闭)引入?

3 个答案:

答案 0 :(得分:2)

要让您的代码正常工作,您需要nonlocal关键字,但这只存在于Python 3中。如果您使用的是Python 2,那么您需要使用一些而是一种解决方法。

一个选项是将外部函数中的值放在可变容器(例如列表)中。内部函数可以将容器变异,即使它不能重新绑定变量:

def f1():
    f1_a = ['f1_a']     # add a list around the value
    def f2():
        f2_a = 'f2_a'
        print 'f2_a={:s}'.format(f2_a)
        print 'f1_a={:s}'.format(f1_a[0])   # read the value from inside the list!
        f1_a[0] = 'f1f2_a'       # mutate the list in place

    f2()
    print 'f1_a={:s}'.format(f1_a[0])   # read from the list here too

虽然上面的代码确实有效,但我强烈建议您升级到Python 3,除非绝对需要保留Python 2以实现向后兼容,或者因为依赖关系不是这些天依赖情况要好得多,因为几乎每个实际维护的项目都已移植到Python 3中,所以如果您使用的是未移植过的东西,那么它就会被移植到Python 3中。可能没有得到任何错误修复。几乎所有新代码都应该专门针对Python 3。

答案 1 :(得分:1)

def f1():
    f1_a = 'f1_a'
    def f2():

        nonlocal f1_a
        f2_a = 'f2_a'
        print('f2_a={:s}'.format(f2_a))
        print('f1_a={:s}'.format(f1_a))
        f1_a = 'f1f2_a'

    f2()
    print('f1_a={:s}'.format(f1_a))

f1()

这将适用于python 3或更高版本,因为nonlocal只能用于python 3或后者

python 2你可以通过这种方式存档

def f1():
    f1.f1_a = 'f1_a'
    def f2():
        f2_a = 'f2_a'
        print('f2_a={:s}'.format(f2_a))
        print('f1_a={:s}'.format(f1.f1_a))
        f1.f1_a = 'f1f2_a'

    f2()
    print('f1_a={:s}'.format(f1.f1_a))

f1()

两者都将推出

f2_a=f2_a
f1_a=f1_a
f1_a=f1f2_a

enter image description here

使用空类

class emptyClass: pass
def f1():
    emp = emptyClass()
    emptyClass.f1_a = 'f1_a'
    def f2():
        f2_a = 'f2_a'
        print('f2_a={:s}'.format(f2_a))
        print('f1_a={:s}'.format(emptyClass.f1_a))
        emptyClass.f1_a = 'f1f2_a'

    f2()
    print('f1_a={:s}'.format(emptyClass.f1_a))

f1()

答案 2 :(得分:1)

Blcknght回答提供了一种实现你想要的方法,但是我想强调你的异常发生是因为你在f2函数中重新绑定 f1_a变量(在f1中定义)。

您可以从附带的函数中访问外部函数变量。

如果在内部函数中删除f1_a的新绑定,则代码在python 2.7中工作:

def f1():
    f1_a = 'f1_a'
    def f2():
        f2_a = 'f2_a'
        print 'f2_a={:s}'.format(f2_a)
        print 'f1_a={:s}'.format(f1_a)
        # f1_a = 'f1f2_a'

    print 'f1_a={:s}'.format(f1_a)
    f2()

>>> f1()
f1_a=f1_a
f2_a=f2_a
f1_a=f1_a

此代码段显示

  

一旦将f1_a重新绑定到另一个对象

,您的代码就会中断

因此,关于您的原始问题 - 您可以从内部函数访问外部函数属性。您还可以改变容器内的值。但重新绑定不可变变量会导致您的问题。