Python在嵌套函数中覆盖variables

假设我有以下的Python代码:

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

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

在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] 

你也可以通过使用函数属性来解决这个问题:

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

澄清:这在Python 2.x和3.x都可以使用。

在我写这个函数的时候,这种情况经常发生在我身上,我突然意识到有一个较小的帮助函数可能是一个好主意,但在其他任何地方都不是很有用。 这自然使我想把它定义为一个嵌套函数。

但我有JAVA匿名对象(即:定义一个可运行的)的经验,并且规则是匿名对象在其外部环境,在这种情况下外部作用域的variables的硬拷贝。 因此,如果外部variables是不可变的( intchar ),它们不能被匿名对象修改,因为它们被复制,而如果它是可变的( collectionobjects ),它们可以被改变…因为它们被复制由“ 指针 ”(他们在内存中的地址)

如果你对编程有所了解,可以把它看作是按价值传递,并通过引用。

在Python中,它是非常相同的。 x=123是一个赋值,它们赋予variablesxa新的含义(不修改旧的x), list[i]/dict[key]是对象访问操作,它们真的修改了事物

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

添加到Sven的答案 :

在Python 2.x中,只能从内部范围读取外部范围variables。 分配只会创build一个新的本地(即内部范围)variables,隐藏外部范围之一。

如果你想读取和修改 ,你可以使用一个dict来保存你的variables在外部作用域,然后通过在内部作用域的字典访问它们,同时保持你的代码相当干净,多个外部作用域:

 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)