Как маринованные объекты травятся?

После прочтения документации маринада у меня сложилось впечатление, что класс должен __reduce__ или же __getstate__ чтобы мариновать правильно. Но как работает травление словарей? У них нет ни одного из этих атрибутов:

> 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, травятся?

5 ответов

Решение

Модуль pickle обрабатывает несколько типов "изначально". Типы, которые он не обрабатывает изначально, должны будут реализовывать "протокол pickle". Dicts и простые подклассы обрабатываются изначально.

__reduce__ а также __getstate__ методы предназначены для того, чтобы быть нижней границей методов выбора, чтобы вы могли реализовать их в своих пользовательских классах, когда они требуют особой обработки от интерпретатора.

Например, если экземпляр класса расширения находится внутри словаря, который вы пытаетесь засолить, это делает весь словарь невосприимчивым, если ваш класс не реализует эти методы, говорящие о том, как его засолить.

Интерпретатор знает, как выбрать встроенные функции, и чтобы выбрать словарь, вы должны использовать pickle.dump или же pickle.dumps метод, не вызывая __reduce__ или же __getstate__,

Травление не требует __reduce__ или же __getstate__, Это методы, которые вы можете использовать для управления засолкой, но засолка будет работать на встроенных типах без них.

Полезный ответ я получил отсюда

Вот что должно быть внутри __getstate__ а также __setstate__, Хотя вы и не можете использовать его сразу, как положено, но вы можете сделать это с нуля, вот так:

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

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

Все хорошие ответы, но они игнорируют вопрос

Кроме того, как классы, полученные из 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 солит, сначала полагаясь на Python, зная, как сериализовать фундаментальные объекты, такие как 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

Мы можем сделать лучше, кстати, если вы используете лучший сериализатор. С помощью dill вместо pickle позволяет сериализовать большинство объектов. Рассол диктата намного сложнее, как вы можете видеть ниже.

>>> 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 сериализует метод класса, потому что есть дополнительные функции, которые были зарегистрированы в dill которые знают, как выбирать и распаковывать более широкий спектр объектов - вы можете увидеть их в разобранном коде (они начинаются с dill.dill). Это гораздо больший рассол, но обычно он работает для любого содержимого, которое вы помещаете в dict,

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

Для классов, происходящих из dictвам не нужно беспокоиться о том, что внутри методов класса могут быть непробиваемые объекты - однако, содержимое пользовательского dict все еще сериализуются с экземпляром класса, так что вам нужно беспокоиться о том, чтобы в вашем классе содержались несериализуемые объекты.

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>

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.'
Другие вопросы по тегам