假设我有一个函数,它在函数内的各个地方重复了大段代码,我可以做到以下几点:
def foo():
def bar():
# do some stuff
bar()
# do some other stuff
bar()
我可以在foo
内“读取”bar
范围内的变量,此外,如果我需要编辑它们,我可以这样做:
def foo():
# stuff involving var1 and var2
def bar():
nonlocal var1, var2
# do some stuff
bar()
# do some other stuff
bar()
问题
现在假设我有几个函数foo_1
,foo_2
,foo_3
...等等,所有这些函数都在bar
中重复相同的代码行。在每个bar
内部定义bar
时,这将是单调的(更不用说每次我想改变foo_i
时的噩梦),但是执行以下操作不起作用,因为它出现{{ 1}}适用于定义函数的范围,而不是调用它的范围:
nonlocal
潜在的解决方案
解决这个问题的一种方法是传递你需要改变的所有变量,然后再返回它们。像这样:
def bar():
nonlocal var1, var2 # SyntaxError: no binding for nonlocal 'var1' found
# do some stuff
def foo_1():
# stuff involving var1 and var2
bar()
# do some other stuff
bar()
我的问题
上述解决方案存在一些问题:
def bar(var1, var2):
# do some stuff
return var1, var2
def foo_1():
# stuff involving var1 and var2
var1, var2 = bar(var1, var2)
# do some other stuff
var1, var2 = bar(var1, var2)
更详细(特别是当有更多变量时)bar()
内定义bar
实际上并没有那么大的改进,因为假设我之前刚刚在foo_i
内访问的变量我现在决定编辑。我不仅需要更改函数,而且还需要在调用它的任何地方进行更改(因为现在我必须返回一个额外的变量)。有没有更好的方法来实现上述目标?
(这感觉就像是一个需要回答的问题,所以如果这是一个重复的问题我会道歉。但我还是找不到任何东西。)
答案 0 :(得分:1)
[...]它似乎是非局部作用于定义函数的范围,而不是它被称为[...]。
你是对的。 nonlocal
仅适用于定义所述函数的命名空间。来自nonlocal
的文档:
非本地语句会使列出的标识符引用最近的封闭范围中先前绑定的变量(不包括全局变量)。
(强调我的)
正如@Aran所提到的,避免不必要的冗长的潜在解决方案是将您想要传递的变量包装到类中的某些函数中。 namedtuple
将是一个有吸引力的选择,因为你不需要一个完整的课程,但正如已经说过的那样,它是不可改变的。您可以使用types.SimpleNamespace
对象,因为它们也是轻量级的:
from types import SimpleNamespace
def bar(n):
n.a = 3, n.b = 4
def foo():
n = SimpleNamespace(a=1, b=2)
bar(n)
print(n.a, n.b) # 3 4
答案 1 :(得分:0)
你可以在每个函数中修改它们之前将这些变量声明为global
,但是它们需要在任何使用它们的函数之前声明,同时请记住这将修改任何函数范围的变量其中它们被声明为全局:
var1 = var2 = None
def bar():
global var1, var2
# do some stuff
def foo_1():
# stuff involving var1 and var2
bar()
# do some other stuff
bar()