Python在嵌套函数中覆盖变量

Ord*_*Ord 53 python scope

假设我有以下python代码:

def outer():
    string = ""
    def inner():
        string = "String was changed by a nested function!"
    inner()
    return string
Run Code Online (Sandbox Code Playgroud)

我想调用outer()来返回"String被嵌套函数改变了!",但我得到了"".我得出结论,Python认为该行string = "string was changed by a nested function!"是对inner()本地新变量的声明.我的问题是:如何告诉Python它应该使用outer()字符串?我不能使用global关键字,因为字符串不是全局的,它只是在外部范围内.想法?

Sve*_*ach 52

在Python 3.x中,您可以使用nonlocal关键字:

def outer():
    string = ""
    def inner():
        nonlocal string
        string = "String was changed by a nested function!"
    inner()
    return string
Run Code Online (Sandbox Code Playgroud)

在Python 2.x中,您可以使用包含单个元素的列表并覆盖该单个元素:

def outer():
    string = [""]
    def inner():
        string[0] = "String was changed by a nested function!"
    inner()
    return string[0]
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用`x = type("",(),{})()`创建这样的"命名空间对象".:) (2认同)
  • @Ord:`nonlocal`将查看除全局范围之外的所有封闭范围 - 毕竟这就是`global`.除了Python 2.x中的上述解决方案之外别无他法 - 这就是为什么引入了`nonlocal`的原因.Python语义说,函数内部的赋值会自动为该函数创建一个局部变量 - 这是一个明智的选择,因为你没有在Python中声明变量,并且编译器必须以某种方式弄清楚变量的范围. (2认同)

cru*_*nk1 24

您还可以使用函数属性解决此问题:

def outer():
    def inner():
        inner.string = "String was changed by a nested function!"
    inner.string = ""
    inner()
    return inner.string
Run Code Online (Sandbox Code Playgroud)

澄清:这适用于python 2.x和3.x.


wat*_*HUN 5

这种情况经常发生在我身上,当我正在编写一个函数时,我突然意识到拥有一个较小的辅助函数可能是个好主意,但在其他任何地方都没有真正的用处。这自然让我想将它定义为嵌套函数。

但我有使用 JAVA 匿名对象的经验(即:定义一个可运行对象),规则是匿名对象制作其外部环境的硬拷贝,在这种情况下是外部范围的变量。因此,如果外部变量是不可变的(int, char),则它们不能被匿名对象修改,因为它们是按复制的,而如果是可变的(collection, objects),则可以更改它们......因为它们是由“指针”复制的(他们在内存中的地址)

如果您了解编程,请将其视为按值传递和按引用传递。

在python中,它非常相似。x=123是赋值,它们赋予变量x一个新的含义(不是修改旧的x),list[i]/dict[key]是对象访问操作,它们真的是修改东西

总而言之,你需要一个可变对象......为了修改(即使你可以使用 [] 访问元组,你不能在这里使用它,因为它不可变)