Python:如何允许'内部函数'更改多个“外部函数”中的非局部变量

时间:2018-04-12 18:18:48

标签: python python-3.x scope python-nonlocal

假设我有一个函数,它在函数内的各个地方重复了大段代码,我可以做到以下几点:

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_1foo_2foo_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内访问的变量我现在决定编辑。我不仅需要更改函数,而且还需要在调用它的任何地方进行更改(因为现在我必须返回一个额外的变量)。

有没有更好的方法来实现上述目标?

(这感觉就像是一个需要回答的问题,所以如果这是一个重复的问题我会道歉。但我还是找不到任何东西。)

2 个答案:

答案 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()