所以我对更有经验的python程序员对以下样式问题的看法感到好奇.假设我正在构建一个函数,该函数将通过pandas数据框或任何类似的用例逐行迭代,其中函数需要访问其先前的状态.似乎至少有四种方法可以在python中实现它:
1)关闭:
def outer(): previous_state = None def inner(current_state) : nonlocal previous_state #do something previous_state=current_state return something
因此,如果你来自javascript背景,这对你来说无疑是显而易见的.在python中感觉很自然,直到你需要访问封闭的范围,当你最终会做类似的事情inner.__code__.co_freevars
,它会给你封闭变量的名称作为元组,并找到你的索引想要,然后去inner.__closure__[index].cell_contents
获得它的价值.不完全优雅,但我认为重点往往是隐藏范围,所以它应该很难达到.另一方面,与OOP语言相比,当几乎所有其他方式都拥有私有变量时,python使封闭函数变为私有也感觉有点奇怪.
2)Functor
def outer(): def inner(current_state): #do something inner.previous_state=current_state return something ret = inner ret.previous_state=None return ret
这"打开了封闭",现在封闭状态作为函数的属性完全可见.这是有效的,因为函数实际上只是伪装的对象.我倾向于这是最pythonic.它清晰,简洁,易读.
3)对象这可能是OOP程序员最熟悉的
class Calculator(Object) : def __init__(self): self.previous_state=None def do_something(self, current_state) : #do_something self.previous_state = current_state return something
这里最大的问题是你最终会得到很多类定义.这对于像Java这样的完全OOP语言来说很好,你可以使用接口等来管理它,但是在一个简化的语言中,有许多简单的类只是为了携带需要一些状态的函数,这似乎有点奇怪.
4)全局 - 我不会证明这一点,因为我特别想避免污染全局名称空间
5)装饰器 - 这是一个有点曲线球,但你可以使用装饰器来存储部分状态信息.
@outer def inner(previous_state, current_state): #do something return something def outer(inner) : def wrapper(current_state) : result = inner(wrapper.previous_state, current_state) wrapper.previous_state = current_state return result ret = wrapper ret.previous_state=None return result
这种语法对我来说是最不熟悉的,但如果我现在打电话
func = inner
我真的得到了
func = outer(inner)
然后反复调用func()
act就像functor示例一样.我其实真的很讨厌这种方式.在我看来,有一个非常不透明的语法,因为很多时候调用内部(current_state)会给你相同的结果,或者每次都会给你一个新装饰的函数,所以这似乎是不好的做法制作以这种方式向函数添加状态的装饰器.
那么哪种方法正确?我错过了哪些优点和缺点?
所以对此的正确答案是可调用对象,它基本上取代了python中闭包的习语.
所以解决上面的选项3变化:
class Calculator(Object) : def __init__(self): self.previous_state=None def do_something(self, current_state) : #do_something self.previous_state = current_state return something
至
class Calculator(Object) : def __init__(self): self.previous_state=None def __call__(self, current_state) : #do_something self.previous_state = current_state return something
现在你可以把它称为函数.所以
func = Calculator(): for x in list: func(x)