2013-11-08 2 views
18

Я знаю, что для того, чтобы быть picklable, класс должен перезаписать метод __reduce__, и он должен возвращать строку или кортеж.Какое точное использование __reduce__ в Pickler

Как работает эта функция? Какое точное использование __reduce__? Когда он будет использоваться?

ответ

36

Я посмотрю, смогу ли я взять удар, объясняя это.

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

Вы можете сообщить модулю рассола, как обращаться с этими типами объектов изнутри непосредственно внутри класса. Давайте построим пример объекта, который имеет одно свойство; открытый дескриптор файла:

import pickle 

class test(object): 
    def __init__(self, file_path = 'test1234567890.txt'): 
     self.some_file_i_have_opened = open(file_path, 'wb') # An open file in write mode. 

my_test = test() 
# Now, watch what happens when we try to pickle this object: 
pickle.dumps(my_test) 

Он должен потерпеть неудачу, и дать отслеживающий:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    --- snip snip a lot of lines --- 
    File "/System/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 file objects 

Однако, если бы мы определили метод __reduce__ в нашем testclass, рассол знал бы, как сериализовать этот объект :

import pickle 

class test(object): 
    def __init__(self, file_path = 'test1234567890.txt'): 
     self._file_name_we_opened = file_path # Used later in __reduce__ 
     self.some_file_i_have_opened = open(self._file_name_we_opened, 'wb') # An open file in write mode. 
    def __reduce__(self): 
     return (self.__class__, (self._file_name_we_opened,)) # we return a tuple of class_name to call, and optional parameters to pass when re-creating 

my_test = test() 
saved_object = pickle.dumps(my_test) 
print repr(saved_object) # Just print the representation of the string of the object, because it contains newlines. 

Это должно дать вам что-то вроде: "c__main__\ntest\np0\n(S'test1234567890.txt'\np1\ntp2\nRp3\n.", который может быть использован для воссоздания объекта с ОПОМ п дескрипторов файлов:

print vars(pickle.loads(saved_object)) 

Как правило, большая путаница с какой тип объекта __reduce__ должен вернуться. в то время как вы можете прочитать немного больше о том, какой тип объекта уменьшить должен вернуться в Документах страниц: http://aakashlabs.org/docs/apl/pyhelp/pydocs/library/pickle.html#pickling-and-unpickling-extension-types, но в целом, нуждается в кортеж, по крайней мере, 2 вещи:

  1. пустой класс объекта для вызова , В этом случае self.__class__
  2. Корень аргументов для перехода к конструктору класса. В этом случае это единственная строка, которая представляет собой путь к открываемому файлу.

Есть и другие необязательные элементы, но вы должны прочитать все о них в документах.

Надеюсь, что это поможет!

+1

Но то же самое может быть достигнуто с помощью '__get_state__',' __set_state__'. – Sklavit

+1

@ Склавит, который лучше использовать? '__get_state__' /' __set_state__' или '__reduce__'? –

+0

@JasonS Как я понимаю '__get_state_' /' __set_state__' - это интерфейс высокого уровня, '__reduce__' - низкий уровень. Поэтому я предпочитаю использовать интерфейс высокого уровня. – Sklavit

Смежные вопросы