2011-03-08 3 views
3

수업을 인스턴스화하는 동안 picklable이 아닌 일부 필드를 초기화합니다. 따라서, 내 수업을 올바르게 (피) 수있게하려면 내 초기화 메서드는 unpickling에 대한 호출 할 싶습니다. 이것은 이전 스타일의 클래스에서 작동하는 것처럼 보입니다.kwargs로 새로운 스타일을 삐걱 거리지 않는 것은 불가능합니까?

새로운 스타일 수업에서는 __new____getnewargs__을 사용해야합니다. 여기에 내가 무엇을 :하지 않을 경우

import cPickle 


class Blubb(object): 

    def __init__(self, value): 
    self.value = value 


class Bla(Blubb): 

    def __new__(cls, value): 
    instance = super(Bla, cls).__new__(cls) 
    instance.__init__(value) 
    return instance 

    def __getnewargs__(self): 
    return self.value, 

    def __getstate__(self): 
    return {} 

    def __setstate__(self, dct): 
    pass 

x = Bla(2) 
print x.value 
pickled = cPickle.dumps(x, 2) 
x_ = cPickle.loads(pickled) 
assert x_.value == 2 

이 사실이 obj = C.__new__(C, *args)를 들어, 잘 될 것입니다. 현재 **kwargs이 있습니다. 따라서 __new____init__ 개의 메소드에서 키워드가 아닌 인수로 제한됩니다.

누구든지 해결 방법을 알고 있습니까? 이것은 정말로 불편합니다.

답변

7

피클 프로토콜 2는 기본적으로 cls.__new__(cls, *args)을 호출하려고하지만이 문제를 해결하는 방법이 있습니다. __reduce__을 사용하면 인수를 __new__에 매핑하는 함수를 반환 할 수 있습니다. 귀하의 예를 수정하여 **kwargs이 작동하도록 할 수있었습니다 :

import cPickle 

class Blubb(object): 

    def __init__(self, value, foo=None, bar=None): 
     self.value = value 
     self.foo = foo 
     self.bar = bar 

def _new_Bla(cls, value, kw): 
    "A function to map kwargs into cls.__new__" 
    return cls.__new__(cls, value, **kw) 

class Bla(Blubb): 

    def __new__(cls, value, **kw): 
     instance = super(Bla, cls).__new__(cls) 
     instance.__init__(value, **kw) 
     return instance 

    def __reduce__(self): 
     kwargs = {'foo': self.foo, 'bar': self.bar} 
     return _new_Bla, (self.__class__, self.value, kwargs), None 

x = Bla(2, bar=[1, 2, 3]) 
pickled = cPickle.dumps(x, 2) 
y = cPickle.loads(pickled) 
assert y.value == 2 
assert y.bar == [1, 2, 3]