2

假设我有一个函数,其中有一大段代码在函数内的各个地方重复,我可以执行以下操作:

def foo():
    def bar():
        # do some stuff

    bar()
    # do some other stuff
    bar()

foo我可以“读取” while inside范围内的变量bar,此外,如果我需要编辑它们,我可以这样做:

def foo():
    # stuff involving var1 and var2
    def bar():
        nonlocal var1, var2
        # do some stuff

    bar()
    # do some other stuff
    bar()

问题

现在假设我有几个函数,, , foo_1...等等,所有这些函数都有相同的代码行,它们都在重复。在 each 内部定义会很单调(更不用说每次我想更改的噩梦) ,但是执行以下操作不起作用,因为它似乎适用于定义函数的范围,而不是调用它的范围:foo_2foo_3barbarbarfoo_inonlocal

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因为假设我以前刚刚在其中访问过的一个变量bar现在决定编辑。我不仅需要更改函数,而且在调用它的任何地方都需要更改(因为现在我必须返回一个额外的变量)。

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

(这感觉就像是那种没有答案的问题,所以如果这是一个重复的问题,我很抱歉。我还没有找到任何东西。)

4

2 回答 2

1

[...] 似乎 nonlocal 在定义函数的范围内起作用,而不是在其中调用它[...]。

你是对的。nonlocal仅适用于定义所述功能的命名空间。从文档中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
于 2018-04-12T18:36:52.943 回答
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()
于 2018-04-12T18:26:51.100 回答