Python在嵌套函数中覆盖变量

时间:2011-10-28 23:43:46

标签: python scope

假设我有以下python代码:

def outer():
    string = ""
    def inner():
        string = "String was changed by a nested function!"
    inner()
    return string

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

4 个答案:

答案 0 :(得分:45)

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

def outer():
    string = ""
    def inner():
        nonlocal string
        string = "String was changed by a nested function!"
    inner()
    return string

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

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

答案 1 :(得分:24)

您还可以使用函数属性来解决这个问题:

def outer():
    def inner():
        inner.string = "String was changed by a nested function!"
    inner.string = ""
    inner()
    return inner.string

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

答案 2 :(得分:4)

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

但我有JAVA匿名对象的经验(即:定义一个runnable),规则是匿名对象制作外部环境的硬拷贝,在这种情况下是外部范围的变量。因此,如果外部变量是不可变的(intchar),则匿名对象不能修改它们,因为它们是由复制的,而如果它是可变的({ {1}},collection),它们可以被更改...因为它们被" 指针"复制(他们在记忆中的地址)

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

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

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

答案 3 :(得分:2)

添加到Sven's answer

在Python 2.x中,您只能从内部范围读取外部范围变量。分配将只创建一个新的本地(即内部范围)变量,该变量隐藏外部范围。

如果您想要阅读和修改,您可以使用dict将变量保存在外部作用域中,然后通过内部作用域中的dict访问它们,同时保持在多个外部范围变量的情况下,您的代码相当干净且可读

def outer():
    # hold some text, plus the number of spaces in the text
    vars = {'text': 'Some text.', 'num_spaces': 1}
    def inner():
        # add some more text
        more_text = ' Then some more text.'
        vars['text'] += more_text
        # keep track of the number of spaces
        vars['num_spaces'] += more_text.count(' ')
    inner()
    return vars['text'], vars['num_spaces']

输出:

>>> outer()
('Some text. Then some more text.', 5)