了解 Python 3 中的非本地

Posted

技术标签:

【中文标题】了解 Python 3 中的非本地【英文标题】:Understanding nonlocal in Python 3 【发布时间】:2014-01-30 13:00:35 【问题描述】:

我正在尝试了解 Python 3 变量范围和nonlocal

考虑以下函数(这只是一个示例):

def build_property(something):

    def deco(func):

        def getter(self):
            return getattr(self, something)

        def setter(self, value):
            setattr(self, something, value)

        return property(getter, setter)

    return deco

没有nonlocal 也可以正常工作。但是,如果现在我想根据 something 有条件地创建 getter 和 setter,我需要非本地的。

def build_property(something):

    def deco(func):

        nonlocal something # This is needed

        if something.startswith('A'):
            getter = None
        else:
            def getter(self):
                return getattr(self, something)

        if something.startswith('B'):
            setter = None
        else:
            def setter(self, value):
                setattr(self, something, value)

        return property(getter, setter)

    return deco

为什么在一种情况下需要nonlocal,而在另一种情况下不需要?换句话说,为什么在第一种情况下正确找到something(没有nonlocal),但在第二种情况下我得到:“UnboundLocalError: local variable 'something' referenced before assignment”如果nonlocal不存在?

【问题讨论】:

...你的问题是?你确实没有说任何关于错误/意外行为的事情。如果您遇到异常,请在您的问题中提供 full 回溯。如果您看到意外的行为,您应该提供 1) 您期望的行为和 2) 您获得的实际输出。我们不是算命的。 只是出于好奇:你的装饰器有什么意义?你似乎没有在任何地方使用func... 顺便说一句,我没有测试代码,但我不明白为什么在第二种情况下需要它,因为something 从未分配给... 在这种情况下需要nonlocal 是不正确的。仅当您分配给something 时才需要nonlocal 【参考方案1】:

首先: nonlocal 在您编写的代码中不是必需的。您不会更改 something 指向的对象。

第二:在某些情况下您需要使用nonlocal。下面是一些需要nonlocal 的代码。请注意,所有断言都是正确的(也就是说,它们不会引发 AssertionError)。

def main():
    variable = 1

    def function():
        variable = 2
    function()
    assert variable == 1

    def function():
        nonlocal variable
        variable = 2
    function()
    assert variable == 2

if __name__ == '__main__':
    main()

第三:您提供的代码不会产生您声称的错误。如果我删除 nonlocal 行并调用以下函数,则不会出现错误。

build_property('A')(lambda: True)
build_property('B')(lambda: True)
build_property('C')(lambda: True)

【讨论】:

【参考方案2】:
def A(d):
    outer = object()
    d["outer"] = outer
    def B():
        print locals()
        assert d["outer"] is outer #This fails and never reaches
        inner = object()
        d=dict()                   #this line.
        print locals()
    def C():
        print locals()
        assert d["outer"] is outer #This goes on fine.
        inner = object()
        print locals()
    return B,C

=> b,c = A(dict())
=> c()
-snip, AOK-
=> b()
UnboundLocalError: local variable 'd' referenced before assignment

对不起,我活该。上面的代码是我快速写出来的,把之前的答案搞得一团糟。

但令人惊讶。我一直认为 python(2.x) 是一种完全没有远见的语言,在最后一刻评估一切......

抱歉现在跑题了。

【讨论】:

我写了一些愚蠢的东西,但它是关于保留父作用域的引用,是的。 这个答案不正确。 nonlocal 不是优化,需要正确识别要创建变量的范围。 Python 2 不会保留所有封闭的局部变量,只保留那些被闭包引用的局部变量 - 与 Python 3 完全一样。不同之处在于 Python 3 允许您更改封闭变量的值没有创建新变量作为副作用。 nonlocal 告诉编译器,尽管赋值发生在内部块中,但被修改的变量是在外部块中创建的变量。

以上是关于了解 Python 3 中的非本地的主要内容,如果未能解决你的问题,请参考以下文章

牛客网精华采集-给双非本/211/非科班

牛客网精华采集-给双非本/211/非科班

牛客网精华采集-给双非本/211/非科班

牛客网精华采集-给双非本/211/非科班

双非本计算机从零开始三年努力能做到什么程度学习路线回顾&总结&问答

双非本计算机从零开始三年努力能做到什么程度学习路线回顾&总结&问答