我有一些类A
的对象,它有自己的方法被pickle,称之为custom_module.customPickle(A)
,它接受A
的实例并返回一个序列化字符串。
我还有包含B
的每个类A
的对象列表。
我需要挑选清单,但是腌制A
会给出一些难以解决的错误。但是,A
有自己的方法可以被腌制。
我可以在课程__reduce__()
中实施B
方法,以便调用custom_module.customPickle(A)
。但是,如何才能使pickle
能够有效地序列化B
?
对象A
是music21.stream
,对象B
是自定义对象。自定义序列化函数为music21.converter.freezeStr(streamObj, fmt=None)
,unpickle函数应为music21.converter.thawStr(strData)
答案 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()
函数,但不会使用相同的挂钩。