2009-12-16 34 views
2

我一直在嘗試醃製一個包含對靜態類方法引用的對象。 泡菜失敗(例如在module.MyClass.foo),說明它不能被醃製,因爲module.foo不存在。
我想出了以下解決方案,使用包裝對象定位在調用的功能,保存容器類和函數名稱:在Python中醃製靜態方法

class PicklableStaticMethod(object): 
    """Picklable version of a static method. 
    Typical usage: 
     class MyClass: 
      @staticmethod 
      def doit(): 
       print "done" 
     # This cannot be pickled: 
     non_picklable = MyClass.doit 
     # This can be pickled: 
     picklable = PicklableStaticMethod(MyClass.doit, MyClass) 
    """ 
    def __init__(self, func, parent_class): 
     self.func_name = func.func_name 
     self.parent_class = parent_class 
    def __call__(self, *args, **kwargs): 
     func = getattr(self.parent_class, self.func_name) 
     return func(*args, **kwargs) 

我很納悶,雖然,有沒有更好的 - 更標準的方法 - 醃這樣的物體? 我不想做出改變全球pickle過程(使用copy_reg爲例),但下面的模式將是巨大的: MyClass類(對象): @picklable_staticmethod 高清富():「做」 打印

我在這方面的嘗試不成功,具體是因爲我無法從foo函數中提取所有者類。我甚至願意爲明確的規範而定居(如@picklable_staticmethod(MyClass)),但我不知道有什麼方法可以將MyClass課程定義在正確的地方。

任何想法都會很棒!

Yonatan

回答

5

這似乎工作。

class PickleableStaticMethod(object): 
    def __init__(self, fn, cls=None): 
     self.cls = cls 
     self.fn = fn 
    def __call__(self, *args, **kwargs): 
     return self.fn(*args, **kwargs) 
    def __get__(self, obj, cls): 
     return PickleableStaticMethod(self.fn, cls) 
    def __getstate__(self): 
     return (self.cls, self.fn.__name__) 
    def __setstate__(self, state): 
     self.cls, name = state 
     self.fn = getattr(self.cls, name).fn 

訣竅是當從中獲取靜態方法時,該類會絆住類。

替代選項:您可以使用元類別爲您的所有靜態方法提供.__parentclass__屬性。然後,您可以繼承Pickler,併爲每個子類實例分配自己的.dispatch表,然後可以在不影響全局分派表(Pickler.dispatch)的情況下對其進行修改。酸洗,取出並調用該方法可能會更快一些。

+0

這不會工作if原來的課程是不可用的,這(我認爲)擊敗了酸洗和取消靜態方法的目的 - 你允許它被醃製,但你需要整個班級取消它。 –

+0

嘗試例如: 進口泡菜 MyClass類(對象): @PickleableStaticMethod DEF DoSomething的(A,B): 打印的a,b 酸洗= pickle.dumps(MyClass.dosomething) 德爾MyClass stm = pickle.loads(pickled) –

+0

我想我可能只是說了一些完全錯誤的地方,pickle與我期望的funcs完全不同。忽略我最近的兩條評論: -/ –

0

編輯:修改後,賈森評論。

我覺得python在不讓酸洗一個靜態方法對象是正確的 - 因爲它是不可能醃製實例或類方法!這樣的對象會做出非常沒有意義的上下文之外:

檢查:Descriptor Tutorial

import pickle 

def dosomething(a, b): 
    print a, b 

class MyClass(object): 
    dosomething = staticmethod(dosomething) 

o = MyClass() 

pickled = pickle.dumps(dosomething) 

這工作,而這應該做什麼 - 定義一個函數,鹹菜它,並使用這些功能某一類的靜態方法。

如果您有需要的用例,請寫下來,我很樂意討論它。

+0

什麼不行的是pickle.dumps(MyClass.dosomething)'。 –

+0

然後這個問題沒有被正確地寫出來,OP說「我一直在嘗試醃一個包含對靜態類方法的引用的對象」,而他真的試圖醃製一個靜態方法,而不是包含對靜態方法引用的對象。 –

+0

讓我用一個例子來說明。 我有一個任務生成機制。例如: MyClass類(TaskGenerator): @staticmethod 高清certain_task(): 打印 「完成任務」 高清generate_task(個體經營): 回報FuncTask(MyClass.certain_task) 我會想,以酸洗產生的任務但目前不能。 我可以使用全局功能 - 並且到現在爲止 - 但我不喜歡從它的「正確位置」取出來支持酸洗。 – Yonatan