簡體   English   中英

在Python中使用閉包和動態定義的函數是一種自然的設計模式嗎?

[英]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.dumpsdill的版本,你會得到有關錯誤g不是相同的功能, g ,而如果你試圖pickle.dumpscloudpickle版本,你會得到關於酸洗本地對象完全相同的錯誤當你開始。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM