2012-04-28 3 views
6

피클 문서를 읽은 후 정확하게 절인하기 위해 클래스가 __reduce__ 또는 __getstate__을 구현해야한다는 인상을 받았습니다. 그런데 어떻게 사전의 절임이 작동합니까? 해당 속성이 없습니다.dict 개체를 절인하는 방법?

> dict(a=1).__reduce__() 

--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
/home/daniyar/work/Apr24/<ipython-input-30-bc1cbd43305b> in <module>() 
----> 1 dict(a=1).__reduce__() 

/usr/lib/python2.6/copy_reg.pyc in _reduce_ex(self, proto) 
    68  else: 
    69   if base is self.__class__: 
---> 70    raise TypeError, "can't pickle %s objects" % base.__name__ 
    71   state = base(self) 
    72  args = (self.__class__, base, state) 

TypeError: can't pickle dict objects 



> dict(a=1).__getstate__() 

--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
/home/daniyar/work/Apr24/<ipython-input-31-00932fb40067> in <module>() 
----> 1 dict(a=1).__getstate__() 

AttributeError: 'dict' object has no attribute '__getstate__' 

또한 dict에서 파생 된 클래스는 절인됩니까?

답변

3

__reduce____getstate__ 메쏘드는 인터프리터로부터 특별한 대우가 필요한 경우 사용자 정의 클래스를 구현하기 위해 산세 방법의 하한을 의미합니다.

예를 들어 피클 링하려는 사전에 확장 클래스의 인스턴스가있는 경우 클래스에서 피클 링하는 방법을 구현하지 않은 클래스는 피할 수없는 전체 사전을 렌더링합니다.

인터프리터 내장 매크로 피클하고, 그렇지 __reduce__ 또는 __getstate__를 호출하여, pickle.dump 또는 pickle.dumps 방법을 사용해야합니다 사전 피클하는 방법을 알고있다.

3

산 세척에는 __reduce__ 또는 __getstate__이 필요하지 않습니다. 그것들은 pickling을 제어하는 ​​데 사용할 수있는 메소드이지만, pickle은 괜찮은 내장 타입에서만 작동합니다.

1

내가 here

에서 가져온 유용한 답은 여기에 __getstate____setstate__ 내부에 있어야하는데 것입니다. 심지어 어떻게 든하지만 당신은 바로가 가정으로 사용할 수는 없지만 다음과 같이 처음부터 그것을 만들 수 있습니다 :

def __getstate__(self): 
    result = self.__dict__.copy() 
    return result 

def __setstate__(self, dict): 
    self.__dict__ = dict 
1

모든 좋은 답변을하지만, 질문 무시 :

을 또한, dict에서 파생 된 클래스를 절인하는 방법?

이들은 다른 클래스와 마찬가지로 참조로 절입니다. 피클을 보면 파이썬이하는 일을 볼 수 있습니다.

>>> class MyDict(dict): 
... def __repr__(self): 
...  return "MyDict({})".format(dict(i for i in self.items())) 
... 
>>> m = MyDict(a=1,b=2) 
>>> m 
MyDict({'a': 1, 'b': 2}) 
>>> import pickle 
>>> # reconstructor called on class MyDict that lives in __main__ 
>>> # and contains a __builtin__ dict with contents ('a' and 'b') 
>>> pickle.dumps(m) 
"ccopy_reg\n_reconstructor\np0\n(c__main__\nMyDict\np1\nc__builtin__\ndict\np2\n(dp3\nS'a'\np4\nI1\nsS'b'\np5\nI2\nstp6\nRp7\n." 
>>> m.clear() 
>>> # removing the contents, to show how that affects the pickle 
>>> pickle.dumps(m) 
'ccopy_reg\n_reconstructor\np0\n(c__main__\nMyDict\np1\nc__builtin__\ndict\np2\n(dp3\ntp4\nRp5\n.' 
>>> # now, just looking at the class itself, you can see it's by reference 
>>> pickle.dumps(MyDict) 
'c__main__\nMyDict\np0\n.' 

또는 동일한 작업을 수행 할 수 있지만 분해 된 피클을 검사 할 수 있습니다. 저장된 지침을 정확히 볼 수 있습니다.

>>> pickletools.dis(pickle.dumps(m)) 
    0: c GLOBAL  'copy_reg _reconstructor' 
    25: p PUT  0 
    28: ( MARK 
    29: c  GLOBAL  '__main__ MyDict' 
    46: p  PUT  1 
    49: c  GLOBAL  '__builtin__ dict' 
    67: p  PUT  2 
    70: (  MARK 
    71: d   DICT  (MARK at 70) 
    72: p  PUT  3 
    75: t  TUPLE  (MARK at 28) 
    76: p PUT  4 
    79: R REDUCE 
    80: p PUT  5 
    83: . STOP 
highest protocol among opcodes = 0 
>>> pickletools.dis(pickle.dumps(MyDict)) 
    0: c GLOBAL  '__main__ MyDict' 
    17: p PUT  0 
    20: . STOP 
highest protocol among opcodes = 0 

클래스가 확실히 참조로 저장되고, 심지어는 dict 대신 object에서 파생 생각했다. 참조는 이름에 대한 것입니다. 즉, __main__ 세션이 닫히면 클래스 정의가 손실되고 MyClass에 종속 된 피클이로드되지 않습니다.

이제 dict을 살펴 보겠습니다.dict 피클은 먼저 dict과 같은 기본 객체를 직렬화하는 방법을 아는 파이썬에 의존합니다 (다른 답변에서 언급했듯이). 그런 다음 내용을 직렬화합니다. 두 개의 strings이 있음을 알 수 있습니다.이 파이썬은 또한 본질적으로 직렬화하는 방법을 알고 있습니다.

즉, 사전에 직렬화 할 수없는 개체가 있으면 실패합니다. 당신이 더 나은 시리얼 라이저를 사용하는 경우

>>> d['c'] = MyDict.__repr__ 
>>> d 
{'a': 1, 'c': <unbound method MyDict.__repr__>, 'b': 2} 
>>> pickle.dumps(d) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps 
    Pickler(file, protocol).dump(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict 
    self._batch_setitems(obj.iteritems()) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 663, in _batch_setitems 
    save(v) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 70, in _reduce_ex 
    raise TypeError, "can't pickle %s objects" % base.__name__ 
TypeError: can't pickle instance method objects 

우리는는, BTW, 더 잘 할 수 . pickle 대신 dill을 사용하면 대부분의 개체를 직렬화 할 수 있습니다. 당신이 아래에서 볼 수 있듯이, dict의 피클은 훨씬 더 복잡합니다. 당신은 (그들이 dill.dill 시작) 디스 어셈블 된 코드에서 볼 수 있습니다 - 피클과 사물의보다 다양한 unpickle하는 방법을 알고 dill에 등록 된 추가 기능이 있기 때문에
>>> import dill 
>>> dill.dumps(d) 
'\x80\x02}q\x00(U\x01aq\x01K\x01U\x01cq\x02cdill.dill\n_load_type\nq\x03U\nMethodTypeq\x04\x85q\x05Rq\x06cdill.dill\n_create_function\nq\x07(cdill.dill\n_unmarshal\nq\x08T$\x01\x00\x00c\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00C\x00\x00\x00s#\x00\x00\x00d\x01\x00j\x00\x00t\x01\x00d\x02\x00\x84\x00\x00|\x00\x00j\x02\x00\x83\x00\x00D\x83\x01\x00\x83\x01\x00\x83\x01\x00S(\x03\x00\x00\x00Ns\n\x00\x00\x00MyDict({})c\x01\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00s\x00\x00\x00s\x15\x00\x00\x00|\x00\x00]\x0b\x00}\x01\x00|\x01\x00V\x01q\x03\x00d\x00\x00S(\x01\x00\x00\x00N(\x00\x00\x00\x00(\x02\x00\x00\x00t\x02\x00\x00\x00.0t\x01\x00\x00\x00i(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>s\t\x00\x00\x00<genexpr>\x03\x00\x00\x00s\x02\x00\x00\x00\x06\x00(\x03\x00\x00\x00t\x06\x00\x00\x00formatt\x04\x00\x00\x00dictt\x05\x00\x00\x00items(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00__repr__\x02\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\t\x85q\nRq\x0bc__builtin__\n__main__\nU\x08__repr__q\x0cNN}q\rtq\x0eRq\x0fNcdill.dill\n_create_type\nq\x10(h\x03U\x08TypeTypeq\x11\x85q\x12Rq\x13U\x06MyDictq\x14h\x03U\x08DictTypeq\x15\x85q\x16Rq\x17\x85q\x18}q\x19(U\n__module__q\x1aU\x08__main__q\x1bh\x0ch\x0fU\x07__doc__q\x1cNutq\x1dRq\x1e\x87q\x1fRq U\x01bq!K\x02u.' 
>>> pickletools.dis(dill.dumps(d)) 
    0: \x80 PROTO  2 
    2: } EMPTY_DICT 
    3: q BINPUT  0 
    5: ( MARK 
    6: U  SHORT_BINSTRING 'a' 
    9: q  BINPUT  1 
    11: K  BININT1 1 
    13: U  SHORT_BINSTRING 'c' 
    16: q  BINPUT  2 
    18: c  GLOBAL  'dill.dill _load_type' 
    40: q  BINPUT  3 
    42: U  SHORT_BINSTRING 'MethodType' 
    54: q  BINPUT  4 
    56: \x85  TUPLE1 
    57: q  BINPUT  5 
    59: R  REDUCE 
    60: q  BINPUT  6 
    62: c  GLOBAL  'dill.dill _create_function' 
    90: q  BINPUT  7 
    92: (  MARK 
    93: c   GLOBAL  'dill.dill _unmarshal' 
    115: q   BINPUT  8 
    117: T   BINSTRING 'c\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00C\x00\x00\x00s#\x00\x00\x00d\x01\x00j\x00\x00t\x01\x00d\x02\x00\x84\x00\x00|\x00\x00j\x02\x00\x83\x00\x00D\x83\x01\x00\x83\x01\x00\x83\x01\x00S(\x03\x00\x00\x00Ns\n\x00\x00\x00MyDict({})c\x01\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00s\x00\x00\x00s\x15\x00\x00\x00|\x00\x00]\x0b\x00}\x01\x00|\x01\x00V\x01q\x03\x00d\x00\x00S(\x01\x00\x00\x00N(\x00\x00\x00\x00(\x02\x00\x00\x00t\x02\x00\x00\x00.0t\x01\x00\x00\x00i(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>s\t\x00\x00\x00<genexpr>\x03\x00\x00\x00s\x02\x00\x00\x00\x06\x00(\x03\x00\x00\x00t\x06\x00\x00\x00formatt\x04\x00\x00\x00dictt\x05\x00\x00\x00items(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00__repr__\x02\x00\x00\x00s\x02\x00\x00\x00\x00\x01' 
    414: q   BINPUT  9 
    416: \x85   TUPLE1 
    417: q   BINPUT  10 
    419: R   REDUCE 
    420: q   BINPUT  11 
    422: c   GLOBAL  '__builtin__ __main__' 
    444: U   SHORT_BINSTRING '__repr__' 
    454: q   BINPUT  12 
    456: N   NONE 
    457: N   NONE 
    458: }   EMPTY_DICT 
    459: q   BINPUT  13 
    461: t   TUPLE  (MARK at 92) 
    462: q  BINPUT  14 
    464: R  REDUCE 
    465: q  BINPUT  15 
    467: N  NONE 
    468: c  GLOBAL  'dill.dill _create_type' 
    492: q  BINPUT  16 
    494: (  MARK 
    495: h   BINGET  3 
    497: U   SHORT_BINSTRING 'TypeType' 
    507: q   BINPUT  17 
    509: \x85   TUPLE1 
    510: q   BINPUT  18 
    512: R   REDUCE 
    513: q   BINPUT  19 
    515: U   SHORT_BINSTRING 'MyDict' 
    523: q   BINPUT  20 
    525: h   BINGET  3 
    527: U   SHORT_BINSTRING 'DictType' 
    537: q   BINPUT  21 
    539: \x85   TUPLE1 
    540: q   BINPUT  22 
    542: R   REDUCE 
    543: q   BINPUT  23 
    545: \x85   TUPLE1 
    546: q   BINPUT  24 
    548: }   EMPTY_DICT 
    549: q   BINPUT  25 
    551: (   MARK 
    552: U    SHORT_BINSTRING '__module__' 
    564: q    BINPUT  26 
    566: U    SHORT_BINSTRING '__main__' 
    576: q    BINPUT  27 
    578: h    BINGET  12 
    580: h    BINGET  15 
    582: U    SHORT_BINSTRING '__doc__' 
    591: q    BINPUT  28 
    593: N    NONE 
    594: u    SETITEMS (MARK at 551) 
    595: t   TUPLE  (MARK at 494) 
    596: q  BINPUT  29 
    598: R  REDUCE 
    599: q  BINPUT  30 
    601: \x87  TUPLE3 
    602: q  BINPUT  31 
    604: R  REDUCE 
    605: q  BINPUT  32 
    607: U  SHORT_BINSTRING 'b' 
    610: q  BINPUT  33 
    612: K  BININT1 2 
    614: u  SETITEMS (MARK at 5) 
    615: . STOP 
highest protocol among opcodes = 2 

Dill

는 클래스 메소드를 직렬화 . 훨씬 더 큰 피클이지만 일반적으로 콘텐츠에 포함 된 콘텐츠는 모두 dict입니다.

dict에서 파생 클래스에 대한
>>> from numpy import * 
>>> everything = dill.dumps(globals()) 

, 당신은 클래스 메소드의 내부 unpicklable 객체를 문제에 대해 걱정할 필요가 없습니다 - 그러나, 내용을 사용자 정의 dict 때문에, 여전히 클래스 인스턴스를 직렬화 당신은 당신의 클래스 내에 포함 된 직렬화 할 수없는 객체들을 갖는 것에 대해 걱정해야한다. lambda

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> 
>>> import pickle 
>>> class MyDict(dict): 
... def __repr__(self): 
...  return "MyDict({})".format(dict(i for i in self.items())) 
... 
>>> m = MyDict(a = lambda x:x) 
>>> m 
MyDict({'a': <function <lambda> at 0x10892b230>}) 
>>> pickle.dumps(a) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'a' is not defined 
>>> pickle.dumps(m) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps 
    Pickler(file, protocol).dump(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 331, in save 
    self.save_reduce(obj=obj, *rv) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 401, in save_reduce 
    save(args) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 562, in save_tuple 
    save(element) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict 
    self._batch_setitems(obj.iteritems()) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 663, in _batch_setitems 
    save(v) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 748, in save_global 
    (obj, module, name)) 
pickle.PicklingError: Can't pickle <function <lambda> at 0x10892b230>: it's not found as __main__.<lambda> 

pickle가 참조 할 수있는 이름을 가지고 있지 않기 때문에 직렬화하는 데 실패합니다. 그러나 dill으로 돌아 가면이 기능을 볼 수 있습니다.

>>> import dill 
>>> dill.dumps(m) 
'\x80\x02cdill.dill\n_create_type\nq\x00(cdill.dill\n_load_type\nq\x01U\x08TypeTypeq\x02\x85q\x03Rq\x04U\x06MyDictq\x05h\x01U\x08DictTypeq\x06\x85q\x07Rq\x08\x85q\t}q\n(U\r__slotnames__q\x0b]q\x0cU\n__module__q\rU\x08__main__q\x0eU\x08__repr__q\x0fcdill.dill\n_create_function\nq\x10(cdill.dill\n_unmarshal\nq\x11T$\x01\x00\x00c\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00C\x00\x00\x00s#\x00\x00\x00d\x01\x00j\x00\x00t\x01\x00d\x02\x00\x84\x00\x00|\x00\x00j\x02\x00\x83\x00\x00D\x83\x01\x00\x83\x01\x00\x83\x01\x00S(\x03\x00\x00\x00Ns\n\x00\x00\x00MyDict({})c\x01\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00s\x00\x00\x00s\x15\x00\x00\x00|\x00\x00]\x0b\x00}\x01\x00|\x01\x00V\x01q\x03\x00d\x00\x00S(\x01\x00\x00\x00N(\x00\x00\x00\x00(\x02\x00\x00\x00t\x02\x00\x00\x00.0t\x01\x00\x00\x00i(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>s\t\x00\x00\x00<genexpr>\x03\x00\x00\x00s\x02\x00\x00\x00\x06\x00(\x03\x00\x00\x00t\x06\x00\x00\x00formatt\x04\x00\x00\x00dictt\x05\x00\x00\x00items(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00__repr__\x02\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x12\x85q\x13Rq\x14c__builtin__\n__main__\nh\x0fNN}q\x15tq\x16Rq\x17U\x07__doc__q\x18Nutq\x19Rq\x1a)\x81q\x1bU\x01aq\x1ch\x10(h\x11U\\c\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00C\x00\x00\x00s\x04\x00\x00\x00|\x00\x00S(\x01\x00\x00\x00N(\x00\x00\x00\x00(\x01\x00\x00\x00t\x01\x00\x00\x00x(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00<lambda>\x01\x00\x00\x00s\x00\x00\x00\x00q\x1d\x85q\x1eRq\x1fc__builtin__\n__main__\nU\x08<lambda>q NN}q!tq"Rq#s}q$b.'