9

所以,我有一个对象,里面有很多不可腌制的东西(pygame 事件、orderedDicts、时钟等),我需要将它保存到磁盘。

问题是,如果我可以让这个东西存储一个有进度的字符串(我只需要一个整数),那么我可以将它传递给对象的 init,它会重建所有这些东西。不幸的是,我正在使用的框架 (Renpy)腌制对象并尝试加载它,尽管我可以将它保存为单个整数,但我无法更改它。

所以,我要问的是,我怎样才能覆盖方法,以便每当pickle 尝试保存对象时,它只保存进度值,而每当它尝试加载对象时,它会从进度值创建一个新实例?

我已经看到了一些关于 __repr__ 方法的讨论,但我不确定如何在我的情况下使用它。

4

2 回答 2

13

您正在寻找的钩子是__reduce__. 它应该返回一个(callable, args)元组;callableand将args被序列化,并且在反序列化时,对象将通过callable(*args). 如果您的类的构造函数采用 int,则可以实现__reduce__

class ComplicatedThing:
    def __reduce__(self):
        return (ComplicatedThing, (self.progress_int,))

您可以将一些可选的额外内容放入元组中,当您的对象图具有循环依赖关系时最有用,但您在这里不需要它们。

于 2015-06-07T23:18:23.460 回答
0

正如 Python 文档所述,虽然 using__reduce__是一种有效的方法:

虽然功能强大,但__reduce__()直接在类中实现很容易出错。因此,类设计者应尽可能使用高级接口(__getnewargs_ex__()__getstate__()__setstate__()

因此,我将解释如何使用更简单的高级接口__getstate__并使__setstate__对象可拾取。

让我们看一个非常简单的类,它有一个不可提取的属性,假设它是一个文件句柄。

class Foo:
    def __init__(self, filename):
        self.filename = filename
        self.f = open(filename)

的实例Foo不可选择:

obj = Foo('test.txt')
pickle.dumps(obj)
# TypeError: cannot pickle '_io.TextIOWrapper' object

__getstate__我们可以通过分别实现和使用 pickle 使这个类可序列化和反序列化__setstate__

class Foo:
    ... # the class as it was
    def __getstate__(self):
       """Used for serializing instances"""
       
       # start with a copy so we don't accidentally modify the object state
       # or cause other conflicts
       state = self.__dict__.copy()

       # remove unpicklable entries
       del state['f']
       return state

    def __setstate__(self, state):
        """Used for deserializing"""
        # restore the state which was picklable
        self.__dict__.update(state)
        
        # restore unpicklable entries
        f = open(self.filename)
        self.f = f

现在可以腌制了:

obj = Foo('text.txt')
pickle.dumps(obj)
# b'\x80\x04\x951\x00\x00\x00\x00\x00\x00\x00\x8c\x08[...]'

因此,在您的示例中,您可能会执行以下操作:

class MyComplicatedObject:
    def __getstate__(self):
        state = self.__dict__.copy()
        del state['progress'] # remove the unpicklable progress attribute
        return state
    def __setstate__(self, state):
        self.__dict__.update(state)
        # restore the progress from the progress integer
        self.progress = make_progress(self.progress_int)

在 Python 3.8+ 中,您还可以为 objects 实现自定义归约

于 2022-01-22T19:11:42.717 回答