Python 3.6 pickling自定义程序

时间:2018-02-13 17:49:58

标签: python pickle

我有一些类A的对象,它有自己的方法被pickle,称之为custom_module.customPickle(A),它接受​​A的实例并返回一个序列化字符串。 我还有包含B的每个类A的对象列表。

我需要挑选清单,但是腌制A会给出一些难以解决的错误。但是,A有自己的方法可以被腌制。

我可以在课程__reduce__()中实施B方法,以便调用custom_module.customPickle(A)。但是,如何才能使pickle能够有效地序列化B

对象Amusic21.stream,对象B是自定义对象。自定义序列化函数为music21.converter.freezeStr(streamObj, fmt=None),unpickle函数应为music21.converter.thawStr(strData)

1 个答案:

答案 0 :(得分:1)

您可以使用copyreg module注册自定义功能进行酸洗和去除污渍;您注册的函数在类上的行为类似于__reduce__ method

如果你返回一个(unpickle_function, state)的元组,那么将调用已注册的unpickle_function可调用来再次取消它,将state作为参数,这样你就可以在那里使用你的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)

(在最近的Python版本中忽略了constructor的{​​{1}}参数)

这会为这些对象注册全局处理程序。您还可以使用每个pickler的调度表,参见[*调度表,了解您如何注册一个。

现在,在进行酸洗时,遇到copyreg Stream的任何实例时,handle_stream()函数用于生成序列化,thawStr()函数将用于再次取消该数据的取消。< / p>

然而music21.converter函数自己使用pickle。他们有效地打包和清理流,然后挑选生成的Stream实例。然后,这将调用自定义处理程序,并且您有一个无限循环。

解决方法是使用自定义dispatch table来处理酸洗和去除污渍。在这种情况下避免使用copyreg,因为它设置了一个全局钩子,每次Stream对象被腌制时都会递归调用。

您自己的泡菜基础设施需要使用自定义选择器:

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()函数,但不会使用相同的挂钩。