我不理解__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
.
我是对的,__reduce__
函数只返回"指令"如果pickle.dumps
调用失败,解构器是否重新创建原始对象?
从文档中我不清楚。
答案 0 :(得分:1)
__reduce__
方法应该返回提示如何重建(unpickle)对象,以防它无法自动pickle。它可能包含一个对象引用和参数,通过它可以调用它来创建对象的初始版本,对象的状态等。
如果返回字符串,则应将该字符串解释为全局变量的名称。它应该是对象相对于其模块的本地名称; pickle模块搜索模块名称空间以确定对象的模块。此行为通常对单身人士有用。
返回元组时,它必须介于2到5个项目之间。可以省略可选项,或者可以提供None作为其值。每个项目的语义都是按顺序排列的:
- 将调用以创建对象初始版本的可调用对象。
- 可调用对象的参数元组。如果callable不接受任何参数,则必须给出一个空元组。
- 可选地,对象的状态,将如前所述传递给对象的
__setstate__()
方法。如果对象没有这样的方法,则该值必须是字典,并且它将被添加到对象的__dict__
属性中。- 可选地,迭代器(而不是序列)产生连续的项目。这些项目将使用
obj.append(item)
或使用obj.extend(list_of_items)
批量附加到对象。这主要用于列表子类,但只要具有适当签名的append()
和extend()
方法,其他类就可以使用它。 (是否使用append()
或extend()
取决于使用的pickle协议版本以及要追加的项目数,因此必须支持两者。)- 可选地,迭代器(不是序列)产生连续的键值对。这些项目将使用
obj[key] = value
存储到对象。这主要用于字典子类,但只要它们实现__setitem__()
,就可以被其他类使用。
答案 1 :(得分:0)
我认为重要的是要注意,在您的示例中使用__reduce__
函数对缺少的错误概不负责。您不仅在使用__reduce__
函数,而且更重要的是,您并没有像以前尝试的那样在__reduce__
函数中腌制打开的文件(请注意,您排除了self.f
__reduce__
函数)。将self.f
添加到__reduce__
函数中,您将遇到相同的错误。