问题
在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'实际上是为本地值创建可变容器的最简单的方法(我相信)。
我认为这种模式有两个值得注意的方面:
这是一个好模式吗?您通常使用哪些替代品?
如果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。
答案 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