假设我有以下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
关键字,因为字符串不是全局的,它只存在于外部范围内。想法?
答案 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),规则是匿名对象制作外部环境的硬拷贝,在这种情况下是外部范围的变量。因此,如果外部变量是不可变的(int
,char
),则匿名对象不能修改它们,因为它们是由值复制的,而如果它是可变的({ {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)