2012-04-28 12 views
6

pickleドキュメントを読んだ後で、正しく節約するために、クラスが__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__のメソッドは、インタープリターから特別な扱いを必要とするときに、カスタムクラスに実装するための酸洗い方法の下限を意味します。

たとえば、拡張クラスのインスタンスがpickleしようとしている辞書の内部にある場合、そのクラスがpickle方法を実装していない場合は、辞書全体をunpickableにレンダリングします。

インタプリタは、組み込みコマンドを酸洗し、そしてあなたがいない__reduce__または__getstate__を呼び出すことにより、pickle.dumpまたはpickle.dumpsメソッドを使用する必要があります辞書をpickle化する方法を知っています。

3

酸洗いには、__reduce__または__getstate__のいずれも必要ありません。これらは、酸洗いを制御するために使用できるメソッドですが、pickleは組み込み型でもうまく機能しません。

1

私はここでhere

から得た有益な答えが__getstate____setstate__の内側にすることになっているものです。何とかそれがなって、あなたはすぐにそれを使用することはできませんが、このように、最初からそれを作ることができるにもかかわらず:

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

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

すべての良い答えが、彼らは質問を無視:

をまた、dictから派生したクラスはどのように漬け込まれますか?

他のどのようなクラスと同様に、それらは参照により漬け込まれます。 pickleを見ると、Pythonが何をしているのかを知ることができます。

>>> 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のような基本オブジェクトをシリアライズする方法を知っているpythonに依存している(他の答えで述べたように)、次に内容をシリアライズします。 2つのstringsがあることがわかります。このPythonも本質的にシリアル化する方法を知っています。

これは、dict内に直列化できないオブジェクトがある場合、失敗することを意味します。あなたがより良いシリアライザを使用する場合

>>> 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 

我々は、ところで、良く行うことができます。 pickleの代わりに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オブジェクトの多種多様を酸洗し、unpickle化する方法を知っているdillに登録されている追加機能がありますので、クラスメソッドをシリアライズ - あなたは逆アセンブルコードの中でそれらを見ることができます(彼らはdill.dillで始まります) 。これははるかに大きなピックルですが、一般的にコンテンツには、dictに入っています。 dictから派生するクラスの場合

>>> from numpy import * 
>>> everything = dill.dumps(globals()) 

、あなたはクラスメソッドの内部でunpickle不可能なオブジェクトを持っていることについて心配する必要はありません - しかし、カスタム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.' 
関連する問題