Python 3.6 酸洗自定义程序

Python 3.6 pickling custom procedure

我有一些 class A 的对象,它们有自己的 pickle 方法,称它为 custom_module.customPickle(A),它采用 A 和 [=41 的实例=] 序列化字符串。 我还有每个 class B 的对象列表,其中包含 A.

我需要 pickle 列表,但是 pickling A 给出了一些难以解决的错误。但是,A有自己的腌制方法。

我可以在 class B 中实现 __reduce__() 方法,以便它调用 custom_module.customPickle(A)。但是我该怎么做才能使 pickle 能够有效地序列化 B


对象 A 是一个 music21.stream,对象 B 是一个自定义对象。自定义序列化函数为music21.converter.freezeStr(streamObj, fmt=None) and the unpickle function should be music21.converter.thawStr(strData)

您可以在 class 上使用 copyreg module to register custom functions for pickling and unpickling; the function you register acts like a __reduce__ method

如果你 return 一个 (unpickle_function, state) 的元组,那么注册的 unpickle_function 可调用函数将被调用以再次解开它,以状态作为参数,所以你可以使用你的 music21.converter.thawStr() 那里的功能:

import copyreg
import music21.converter
import music21.stream


def pickle_music21_stream(stream_obj):
    return music21.converter.thawStr, (music21.converter.freezeStr(stream_obj),)

copyreg.pickle(music21.stream.Stream, pickle_music21_stream)

copyregconstructor 参数在最近的 Python 版本中被忽略)

这会为这些对象注册一个全局 处理程序。您还可以为每个 pickler 使用一个 dispatch table,请参阅 [*Dispatch Tables 了解如何注册一个。

现在,当 pickling 遇到 Stream 的任何实例时,handle_stream() 函数用于生成序列化,thawStr() 函数将用于再次对该数据进行 unpickle .

但是music21.converter 函数本身使用 pickle。他们有效地打包和清理流,然后腌制生成的 Stream 实例。然后这将调用自定义处理程序,并且你有一个无限循环。

解决方法是使用自定义 dispatch table 来处理 pickling 和 unpickling。在这种情况下避免使用 copyreg,因为它设置了一个全局挂钩,每次 Stream 对象被 pickle 时都会递归调用该挂钩。

您自己的 pickle 基础设施需要使用自定义 pickler:

import copyreg
import io
import pickle
import music21.converter
import music21.stream


def pickle_music21_stream(stream_obj):
    return music21.converter.thawStr, (music21.converter.freezeStr(stream_obj),)


def dumps(obj):
    f = io.BytesIO()
    p = pickle.Pickler(f)
    p.dispatch_table = copyreg.dispatch_table.copy()
    p.dispatch_table[music21.stream.Stream] = pickle_music21_stream
    p.dump(obj)
    return f.getvalue()


def loads(data):
    return pickle.loads(data)  # hook is registered in the pickle data

只有在您自己的数据结构中找到 Stream 实例时,才会调用自定义函数。 music21 例程使用全局 pickle.dumps()pickle.loads() 函数,不会使用相同的钩子。