[英]Is it a natural design pattern to use closures and dynamically defined functions in Python?
我发现定义函数要求用户定义然后将另一个函数传递给我是一个非常自然的设计模式。 例如,
def gradient_descent(x0, grad_f):
x = x0
for _ in range(100):
x -= 0.1 * grad_f(x)
return x
实现通用梯度下降例程; 用户所要做的就是为f定义渐变函数。 这基本上是scipy.optimize使用的接口,我编写的程序倾向于以类似的方式使用各种函数闭包和动态定义的函数。
但是,我发现自己在利用多处理的并行性方面遇到了一些严重的困难,因为函数无法被腌制。 我知道有很多方法可以解决这个问题,但这让我怀疑这样的编程是否是一种“pythonic”的做事方式。
这是Python中的自然设计模式吗? 是否有更好的方法来设计可能需要重构以使用多个流程的程序?
这完全是Pythonic,但你必须为你的闭合写一个pickler。
Python不会自动为您执行此操作,因为您可能需要一些不同的选项。 特别是,你必须决定你想要“伪造封闭性”的程度。 您是否只想复制捕获的值? 或者你想复制整个堆栈框架并从中捕获单元格? 或者您是否希望实际插入Manager
等,以强制捕获与父级保持同步?
一旦确定要应用的确切规则,就可以编写执行该操作的代码。 阅读pickle
文档了解详细信息,还可以查看multiprocessing
文档和链接源,以了解它如何以其他方式扩展pickle
。
但好消息是,你想要的最有可能是dill
所做的,或者恰恰是什么样的cloudpickle
。
一般来说:
dill
尝试尽可能便携,因此您可以将泡菜保存到磁盘并在以后使用它们,即使这意味着您可能不关心的一些事情在封面下略有不同。 cloudpickle
试图尽可能准确,即使这意味着泡菜不能用于任何东西,只能是你的过程的精确克隆。 如果它们都不是你想要的,你当然可以查看两者的来源,并找出如何做到你想要的。 这是一个微不足道的关闭:
def f():
def g(): return i
i=1
return g
g = f()
相比:
>>> pickle.dumps(g)
AttributeError: Can't pickle local object 'f.<locals>.g'
>>> dill.loads(dill.dumps(g))
<function __main__.g>
>>> dill.loads(dill.dumps(g)).__closure__
(<cell at 0x108819618: int object at 0x1009e0980>,)
>>> dill.loads(dill.dumps(g))()
1
>>> cloudpickle.loads(cloudpickle.dumps(g))
<function __main__.f.<locals>.g>
>>> cloudpickle.loads(cloudpickle.dumps(g)).__closure__
(<cell at 0x108819618: int object at 0x1009e0980>,)
>>> cloudpickle.loads(cloudpickle.dumps(g))()
1
请注意,它们都会生成一个闭包,捕获一个引用值1的单元格,但cloudpickle
的名称恰好是正确的,而dill
没有。 如果您尝试pickle.dumps
的dill
的版本,你会得到有关错误g
不是相同的功能, g
,而如果你试图pickle.dumps
的cloudpickle
版本,你会得到关于酸洗本地对象完全相同的错误当你开始。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.