【问题标题】:What's the exact usage of __reduce__ in PicklerPickler中__reduce__的确切用法是什么
【发布时间】:2013-11-08 09:05:37
【问题描述】:

我知道,一个类必须覆盖__reduce__ 方法,并且它必须返回字符串或元组。

这个功能是如何工作的? __reduce__ 的具体用法是什么?什么时候使用?

【问题讨论】:

  • 请注意:一个类不必覆盖__reduce__ 方法就可以被picklable。至少在最新版本的 Python 中是这样。正如documentation states“在大多数情况下,不需要额外的代码来使实例变得可挑选。”

标签: python pickle


【解决方案1】:

当您尝试腌制一个对象时,可能有一些属性不能很好地序列化。其中一个示例是打开的文件句柄。 Pickle 不知道如何处理该对象并会抛出错误。

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

import pickle

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

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

但是,如果我们在 Test 类中定义了 __reduce__ 方法,pickle 就会知道如何序列化这个对象:

import pickle

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

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

这应该会给你类似:"c__main__\nTest\np0\n(S'test1234567890.txt'\np1\ntp2\nRp3\n.",它可以用来重新创建带有打开文件句柄的对象:

print(vars(pickle.loads(saved_object)))

一般情况下,__reduce__ 方法需要返回一个至少包含两个元素的元组:

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

请咨询docs,详细了解__reduce__ 方法还可以返回什么。

【讨论】:

  • 但同样可以使用__get_state__, __set_state__
  • @Sklavit 哪个更好用? __get_state__/__set_state____reduce__?
  • @JasonS 据我了解__get_state_/__set_state__ 是高级接口,__reduce__ - 低级。所以我更喜欢使用高级接口。
  • 我是否正确理解 __getstate__ 在定义 __reduce__ 时不会被调用?
  • Pickling 对象大概是记录对象的当前状态。文件句柄是包含大量自身状态的属性的一个很好的示例,仅重新打开文件不足以恢复 test 对象的状态。您还想记录self.some_file_i_have_opened.tell()test 类感兴趣的任何其他状态。有关更完整的示例,请参阅 docs.python.org/3/library/pickle.html#handling-stateful-objects(使用 __get_state__/__set_state__)。
猜你喜欢
  • 1970-01-01
  • 2014-03-21
  • 2010-11-25
  • 1970-01-01
  • 1970-01-01
  • 2018-05-13
  • 2020-04-26
  • 2013-12-01
  • 2014-11-23
相关资源
最近更新 更多