我有以下代码:
def decorator(func):
@functools.wraps(func)
def other_func():
print('other func')
return other_func
@decorator
def func():
pass
如果我尝试腌制func
,则一切正常。但是,如果将模块编译为Cython扩展,则它将失败。
这是错误:
>>>> pickle.dumps(module.func)
PicklingError: Can't pickle <cyfunction decorator.<locals>.other_func at 0x102a45a58>: attribute lookup other_func on module failed
如果我使用dill
而不是pickle
,也会发生同样的情况。
您知道如何解决吗?
答案 0 :(得分:2)
我认为您在这里真的无能为力。看起来像Cython中的一个可能错误。但是Cython为何做我不知道的事情可能有充分的理由。
出现问题是因为Cython函数在Python领域中作为内置函数公开(例如map
,all
等)。这些功能不能更改其名称属性。但是,Cython试图使其功能更像纯Python函数,因此可以对其某些属性进行修改。但是,Cython函数还实现了__reduce__
,它可以定制pickle
序列化对象的方式。似乎此函数确实认为可以更改函数对象的名称,因此忽略了这些值,并使用了被包装的内部PyCFunction结构的名称(github blob)。
最好的办法是提交错误报告。您可能能够创建一个精简包装,而不是使您的函数序列化,但这会在调用函数时增加开销。
您可以使用persistent_id
和Pickler
的{{1}}功能来覆盖Cython提供的自定义实现。以下是如何自定义特定类型/对象的酸洗。它是通过纯python函数完成的,但您可以轻松更改它以处理Cython函数。
Unpickler