0

在 Mark Lutz 的“Learning 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: global name 'f1_a' is not defined) 和 'nonlocal' (nonlocal f1_a , SyntaxError: invalid syntax) 不起作用。这是否意味着无法将外部函数中引入的变量从内部(直接封闭的)变量中更改?

4

3 回答 3

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。

于 2018-04-11T08:26:25.293 回答
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

在此处输入图像描述

使用空类

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()
于 2018-04-11T08:28:19.570 回答
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 重新绑定到另一个对象,您的代码就会中断

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

于 2018-04-11T08:34:32.453 回答