Pickler中__reduce__的确切用法是什么?

oyj*_*yjh 36 pickle python-2.7

我知道,为了被picklable,类必须覆盖__reduce__方法,并且必须返回字符串或元组.

这个功能如何运作?具体用途是__reduce__什么?它何时被使用?

Voo*_*OFX 59

我会看看我是否可以尝试解释这一个.

每当您尝试挑选一个对象时,都会有一些可能无法很好地序列化的属性.例如,一个打开的文件句柄在这种情况下,pickle将不知道如何处理该对象并将抛出错误.

您可以告诉pickle模块如何直接在类中本地处理这些类型的对象.让我们构建一个具有单个属性的对象的示例; 一个打开的文件句柄:

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)
Run Code Online (Sandbox Code Playgroud)

它应该失败,并给予追溯:

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
Run Code Online (Sandbox Code Playgroud)

但是,如果我们在我们中定义了一个__reduce__方法test class,那么pickle会知道如何序列化这个对象:

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.
Run Code Online (Sandbox Code Playgroud)

这应该给你类似于:"c__main__\ntest\np0\n(S'test1234567890.txt'\np1\ntp2\nRp3\n.",可用于使用打开的文件句柄重新创建对象:

print vars(pickle.loads(saved_object))
Run Code Online (Sandbox Code Playgroud)

通常,最大的困惑是__reduce__应该返回什么类型的对象.虽然你可以阅读更多关于什么类型的对象减少应该在文档页面中返回的内容:http://aakashlabs.org/docs/apl/pyhelp/pydocs/library/pickle.html#pickling-and-unpickling-extension-类型,但一般来说,它需要至少2件事的元组:

  1. 要调用的空白对象类.在这种情况下,self.__class__
  2. 传递给类构造函数的参数元组.在这种情况下,它是一个字符串,它是要打开的文件的路径.

还有其他可选项,但您应该在文档中阅读所有相关内容.

希望有所帮助!

  • @Sklavit 哪个更好用?`__get_state__`/`__set_state__` 还是 `__reduce__`? (3认同)
  • @JasonS 据我了解,`__get_state_`/`__set_state__`是高级接口,`__reduce__`是低级接口。所以我更喜欢使用高级接口。 (3认同)
  • 我是否正确理解定义“__reduce__”时不会调用“__getstate__”? (3认同)
  • Pickle 对象大概是为了记录对象的_当前状态_。文件句柄是一个很好的属性示例,它包含许多自己的状态,仅重新打开文件不足以恢复“test”对象的状态。您还需要记录“self.some_file_i_have_opened.tell()”以及“test”类感兴趣的任何其他状态。有关更完整的示例,请参阅 https://docs.python.org/3/library/pickle.html#handling-stateful-objects (使用 `__get_state__`/`__set_state__` )。 (3认同)
  • 但使用`__get_state__`,`__ set_state__`可以实现同样的目的. (2认同)