【问题标题】:How __reduce__ function exactly works in case of pickle module?在 pickle 模块的情况下,__reduce__ 函数究竟如何工作?
【发布时间】:2016-08-07 10:28:40
【问题描述】:

我不明白 __reduce__ 函数在 Python 中 pickle 模块的情况下是如何工作的。

假设我有以下课程:

class Foo(object):
  def __init__(self, file_name = 'file.txt'):
    self.file_name = file_name
    self.f = open(self.file_name, 'w')

不能腌制因为pickle模块不知道如何编码文件句柄:

foo = Foo()
print(pickle.dumps(foo))

输出:

TypeError: can't pickle file objects

但如果我添加 __reduce__ 函数,它会成功编码:

import pickle

class Foo(object):
  def __init__(self, file_name = 'file.txt'):
    self.file_name = file_name
    self.f = open(self.file_name, 'w')

  def __reduce__(self):
    return (self.__class__, (self.file_name, ))

foo = Foo()
print(pickle.dumps(foo))

输出:

c__main__
Foo
p0
(S'file.txt'
p1
tp2
Rp3
.

如果pickle.dumps 调用失败,__reduce__ 函数只是返回“指令”让解构器重新创建原始对象,这对吗?

从文档中我不清楚。

【问题讨论】:

    标签: python serialization pickle


    【解决方案1】:

    你是对的。 __reduce__ 方法应返回提示如何重建(取消腌制)对象,以防无法自动腌制。它可能包含一个对象引用和参数,将调用它来创建对象的初始版本、对象的状态等。

    来自documentation

    如果返回一个字符串,则该字符串应被解释为一个全局变量的名称。它应该是对象相对于其模块的本地名称; pickle 模块搜索模块命名空间以确定对象的模块。这种行为通常对单例有用。

    返回元组时,它的长度必须在 2 到 5 个之间。可选项目可以省略,也可以提供 None 作为它们的值。每个项目的语义是按顺序排列的:

    • 将被调用以创建对象的初始版本的可调用对象。
    • 可调用对象的参数元组。如果可调用对象不接受任何参数,则必须给出一个空元组。
    • (可选)对象的状态,如前所述,它将传递给对象的 __setstate__() 方法。如果对象没有这样的方法,那么该值必须是一个字典,它将被添加到对象的__dict__ 属性中。
    • (可选)产生连续项的迭代器(而不是序列)。这些项目将使用obj.append(item) 或批量使用obj.extend(list_of_items) 附加到对象。这主要用于列表子类,但可以由其他类使用,只要它们具有具有适当签名的append()extend() 方法。 (是否使用append()extend() 取决于使用的pickle 协议版本以及要附加的项目数量,因此必须同时支持。)
    • (可选)生成连续键值对的迭代器(不是序列)。这些项目将使用obj[key] = value 存储到对象中。这主要用于字典子类,但可以被其他类使用,只要它们实现了__setitem__()

    【讨论】:

      【解决方案2】:

      我认为重要的是要注意,在您的示例中使用 __reduce__ 函数不会导致没有引发错误。您不仅在使用__reduce__ 函数,而且更重要的是,您不会像之前尝试的那样尝试在__reduce__ 函数中腌制打开的文件(请注意,您在__reduce__ 函数中排除了self.f) .将self.f 添加到__reduce__ 函数中,您会遇到同样的错误。

      【讨论】:

      • 好吧,pickle 的默认行为是复制被腌制对象的整个__dict__,包括不能被腌制的self.f 文件。使用__reduce__ 函数 阻止它执行此默认行为的原因,因此 对没有引发错误负责。当然你是对的,__reduce__ 版本起作用的原因是它不会尝试腌制有问题的self.f,而是以另一种方式重建对象。
      猜你喜欢
      • 2019-01-05
      • 1970-01-01
      • 2020-08-22
      • 2013-05-06
      • 2017-01-17
      • 2021-09-21
      • 2019-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多