使用类作为局部变量的容器对象,作为Python中“非局部”的替代

时间:2017-11-01 22:57:50

标签: python python-3.x

问题

在Python中,如果我有一个带局部变量和嵌套函数的函数,我可以借助非局部函数在嵌套函数中分配这些变量:

def f():
    x = 0
    def _g():
        nonlocal x
        x = 1
    def _h():
        x = 2
    _g()
    _h()
    print(x)
f() # 1

我对这个解决方案的问题是,如果我在f()中有很多局部变量,那么使用非局部是冗长的,更令人不安的是,很容易忘记变量的非局部变量,并且在变量中创建局部变量嵌套函数没有注意到它(例如,我在上面的h()函数中的意思是什么?)。

我已经看过并使用过另一种选择:

def f():
    class state:
        x = 0
    def _g():
        state.x = 1
    def _h():
        x = 2
    _g()
    _h()
    print(state.x)
f() # 1

如果使用Python中的类实际上也是一个对象的事实。以这种方式使用'class'实际上是为本地值创建可变容器的最简单的方法(我相信)。

我认为这种模式有两个值得注意的方面:

  • 'class'-keyword的特定用法可能会被视为黑客。
  • 由于容器有点人为,有时很难为它找到一个好名字(我到目前为止测试使用'self'这个名称,但这看起来更像是一个hack)。 / LI>

这是一个好模式吗?您通常使用哪些替代品?

如果StackOverflow不是这个问题的正确论坛,请告知您认为更适合的其他论坛(我确实阅读了常见问题解答,但对于这个问题,正确的论坛对我来说并不明显)。

提前致谢。

P.S。

为了完整起见,至少有一个替代方案,感觉更像是黑客:

class f:
    def __init__(self):
        self.x = 0
        self._g()
        self._h()
        print(self.x)
    def _g(self):
        self.x = 1
    def _h(self):
        x = 2
f() # 1

这是有效的,因为在Python中,类实例化具有与函数调用相同的语法。

答案

请参阅下面接受的答案。有关函数需要返回值时的解决方案的讨论,请参阅there

2 个答案:

答案 0 :(得分:3)

你的"最后的手段" alernative当然更清晰 - 如果你可以在共​​享状态的扁平方法中执行它,那么代码比嵌套函数更可读,以执行相同的工作。 " Flat优于嵌套"。

除此之外,您正在创建一个具有命名空间的类。您可以简单地创建一个对象作为命名空间,它可以作为命名空间 - 这是更常见的。唯一的问题是,如果你只是创建一个object本身的实例,它就不能作为名称空间,因为它没有__dict__,所以你不能自由地定义对象对此。

这就是为什么在stdlib的types模块中隐藏了一个名为SimpleNamespace的类,这个用例恰好适用于此用例。

只是做:

from types import SimpleNamespace

def f():
    state = SimpleNamespace()
    state.x = 0
    ...

(但是,只有当你不改变主意并选择基于阶级的解决方案时才会更清洁。)

答案 1 :(得分:1)

为什么不使用dict而不是类。这消除了一些" hackyness"并且与Python 2兼容:

def f():
    state=dict(x=0)

    def _g():
        state["x"] = 1

    def _h():
        x = 2
    _g()
    _h()
    print(state["x"])
f() # 1