【问题标题】:Local functions in PythonPython 中的局部函数
【发布时间】:2010-11-27 17:02:38
【问题描述】:

在以下 Python 代码中,我得到一个 UnboundLocalError。据我了解,局部函数共享包含函数的局部变量,但这里似乎并非如此。我认识到 a 在这种情况下是一个不可变的值,但这应该不是问题。

def outer():
    a = 0
    def inner():
        a += 1
    inner()
outer()

内部函数似乎已收到父函数中所有引用的副本,因为如果 a 的值包装在可变类型中,我不会收到 UnboundLocalError 异常。

是否有人能够澄清这里的行为,并指出相应的 Python 文档?

【问题讨论】:

标签: python function binding model local


【解决方案1】:

我相信您将其视为“可变性”问题是正确的。虽然您发布的代码确实会引发“UnboundLocalError”,但以下代码不会:

def outer():
    a = 0
    def inner():
        print a
    inner()
outer()

Python 不允许您在内部范围内从外部范围重新分配变量的值(除非您使用关键字“global”,在这种情况下不适用)。

查看此 Python 2.6.2 文档中“类”文档的底部部分:

9.2. Python Scopes and Namespaces

[…] 如果一个名字被声明为全局的,那么所有的引用和赋值都会去 直接指向包含模块全局名称的中间范围。 否则,在最内层范围之外找到的所有变量都是 只读(尝试写入此类变量只会创建一个 最内层范围内的新局部变量,保持相同 命名外部变量不变)。

您的“UnboundLocalError”是因为您的函数实际上是在声明一个名为“a”的新变量,然后立即尝试对其执行“+=”操作,但这会失败,因为“a”还没有值。 (将“a+=1”视为“a = a+1”,如果“a”未定义,则可以看出问题)。

一般来说,如果您要修改“a”,人们通常绕过它的方法是使用可变类型来传递“a”(例如列表或字典)。您可以通过可变类型的内容修改“a”(正如您在使用此设置进行测试时可能注意到的那样)。

希望有帮助!

【讨论】:

  • 是的,我相信内部正在接收所有外部参考的副本。然而,在分配给不可变的时,新值仅绑定到内部函数范围。
  • 我想我现在唯一的问题是 locals() != 您链接到的文档中描述的“最内层范围”。
  • 顺便说一句,Python3 通过添加非本地语句来解决这个问题:docs.python.org/3.1/reference/…
  • 感谢上帝!这只是推动使用 Python 3 的另一个原因。
  • 代码在定义内部函数时很容易缩进,最终违反了 79 chars PEP8 建议。有什么办法可以解决这个问题?内部函数可以以某种方式放置在外部函数之外吗?我知道这个问题听起来很愚蠢,但我是认真的。
【解决方案2】:

你应该将你的变量指定为非本地变量以保持它在闭包中的状态,所以定义应该是这样的

def outer():
    a = 0
    def inner():
        nonlocal a
        a += 1
    inner()

【讨论】:

【解决方案3】:

尝试将变量绑定为参数。

def outer():
    a = 0
    def inner(a=a):
        a += 1

    inner()

outer()

我会尝试挖掘相应的文件。

编辑

由于您希望内部函数对外部范围产生副作用,因此您需要使用可变数据类型,如列表。整数和字符串是不可变的。

def outer():
    a = [0]
    def inner():
        a[0] += 1
    inner()
    print a[0]
outer()

【讨论】:

  • 我在旧版 Python 的文档中找到了这个建议。还有一个问题是增加a 不会影响outer() a。
  • 如果你想让它有副作用,那么你需要为a使用可变类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多