2009-12-16 5 views
2

정적 클래스 메서드에 대한 참조를 포함하는 개체를 피클링하려고했습니다. 피클은 절임 될 수 없다는 진술서 (예 : module.MyClass.foo)와 일치하지 않습니다. module.foo은 존재하지 않습니다. 더 표준적인 방법 - 더 나은가, 그래도 궁금Python에서 정적 메서드 pickling

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) 

:
나는 컨테이너 클래스와 함수 이름을 저장, 호출시 기능을 찾을 래퍼 객체를 사용하여 다음과 같은 솔루션과 함께 올라와있다 - 그런 피클 피클? I (예 : copy_reg 사용) 글로벌 pickle 과정을 변경하지 않지만, 다음과 같은 패턴은 좋은 것 : MyClass 클래스 (객체) : @picklable_staticmethod 데프 foo는() ". 다" 인쇄

내 시도는 성공하지 못했습니다. 특히 foo 함수에서 소유자 클래스를 추출 할 수 없었기 때문입니다. 심지어는 명시 적 사양 (예 : @picklable_staticmethod(MyClass))으로 해결할 의향이 있었지만 정의되고있는 곳의 MyClass 클래스를 참조하는 방법을 알지 못합니다.

모든 아이디어가 우수 할 것입니다.

요나탄

답변

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)에 영향을 미치지 않고 수정할 수 있습니다. Pickling, unpickling, 메소드 호출은 조금 더 빠를 수도 있습니다.

+0

원래 클래스는 사용할 수 없습니다. (나는 생각합니다) 정적 메서드를 산정 및 unpickling의 목적을 패배 - 당신은 그것을 절어 수 있지만 전체 클래스를 unpickle 필요합니다. 수입 피클 MyClass 클래스 (객체) : 절인 =의 pickle.dumps (MyClass.dosomething) 델 B, 인쇄 A : 가 데프 (A, B)을 해봐요 @PickleableStaticMethod –

+0

는 예를 들어 것을 시도 MyClass stm = pickle.loads (절임) –

+0

나는 그저 완전히 잘못된 것을 말했을 것이고, pickle은 내가 기대했던 funcs와 완전히 다른 것으로 생각한다. 최근의 두 코멘트를 무시하십시오. -/ –

0

편집 : 제이슨 코멘트 이후 수정.

필자는 파이썬이 staticmethod 객체를 제거하지 않는 것이 맞다고 생각합니다. 인스턴스 또는 클래스 메소드를 피할 수 없으므로! 이러한 객체는 컨텍스트 외부에서 약간의 감각을 만들 것 :

확인이 : Descriptor Tutorial

import pickle 

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

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

o = MyClass() 

pickled = pickle.dumps(dosomething) 

이 작동하고, 그 수행해야 무슨 - 함수, 피클에게 그것을 정의하고, 같은 기능을 사용하여 특정 클래스의 static 메소드.

필요에 따라 유스 케이스가 있다면 작성하여 기꺼이 토론 해주십시오.

+0

'pickle.dumps (MyClass.dosomething)'은 효과가 없을 것입니다. –

+0

그러면 문제는 제대로 쓰여지지 않습니다. OP는 "정적 클래스 메쏘드에 대한 참조를 포함하고있는 객체를 피클하려고했습니다."라고 말합니다. 정적 메쏘드에 대한 참조가 들어있는 객체가 아니라 정적 메쏘드를 정말로 피클하려고합니다. –

+0

예를 들어 설명해 드리겠습니다. 나는 작업 생성 메커니즘을 가지고있다.예를 들면 : MyClass 클래스 (TaskGenerator) : 반환 FuncTask (MyClass.certain_task) 내가 생성 된 작업을 피클 할 것 @staticmethod 데프 certain_task() : 데프 (자신을) generate_task 인쇄 "수행 작업" 그러나 현재는 할 수 없다. 전 세계적인 기능을 사용할 수 있습니다 - 그리고 지금까지 가지고 -하지만 절름발이 지원에 찬성하여 '올바른 장소'에서 꺼내는 것이 싫습니다. – Yonatan