gpt4 book ai didi

python - pickle Cython 修饰函数导致 PicklingError

转载 作者:太空宇宙 更新时间:2023-11-04 02:10:46 27 4
gpt4 key购买 nike

我有以下代码:

def decorator(func):

@functools.wraps(func)
def other_func():
print('other func')

return other_func

@decorator
def func():
pass

如果我尝试 pickle 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,也会发生同样的情况。

你知道怎么解决吗?

最佳答案

我认为您在这里无能为力。它看起来像是 Cython 中可能存在的错误。但可能有一个很好的理由来解释为什么 Cython 会做我不知道的事情。

问题的出现是因为 Cython 函数在 Python 领域中作为内置函数公开(例如 mapall 等)。这些函数不能更改其名称属性。然而,Cython 试图使其函数更像纯 Python 函数,因此提供了修改其多个属性的能力。但是,Cython 函数还实现了 __reduce__,它自定义了对象如何被 pickle 序列化。看起来这个函数确实认为可以更改函数对象的名称,因此忽略这些值并使用正在包装的内部 PyCFunction 结构的名称(github blob)。

您能做的最好的事情就是提交错误报告。您可能能够创建一个薄包装器,而不是使您的函数被序列化,但这会在函数被调用时增加开销。

自定义 Pickle

您可以使用 PicklerUnpicklerpersistent_id 功能来覆盖 Cython 提供的自定义实现。以下是如何为特定类型/对象自定义 pickle 。它是使用纯 Python 函数完成的,但您可以轻松地对其进行更改以处理 Cython 函数。

import pickle
from importlib import import_module
from io import BytesIO

# example using pure python
class NoPickle:
def __init__(self, name):
# emulating a function set of attributes needed to pickle
self.__module__ = __name__
self.__qualname__ = name

def __reduce__(self):
# cannot pickle this object
raise Exception


my_object = NoPickle('my_object')

# pickle.dumps(obj) # error!

# use persistent_id/load to help dump/load cython functions

class CustomPickler(pickle.Pickler):
def persistent_id(self, obj):
if isinstance(obj, NoPickle):
# replace with NoPickle with type(module.func) to get the correct type
# alternatively you might want to include a simple cython function
# in the same module to make it easier to get the write type.
return "CythonFunc" , obj.__module__, obj.__qualname__
else:
# else return None to pickle the object as normal
return None

class CustomUnpickler(pickle.Unpickler):
def persistent_load(self, pid):
if pid[0] == "CythonFunc":
_, mod_name, func_name = pid
return getattr(import_module(mod_name), func_name)
else:
raise pickle.UnpicklingError('unsupported pid')

bytes_ = BytesIO()
CustomPickler(bytes_).dump(my_object)

bytes_.seek(0)
obj = CustomUnpickler(bytes_).load()

assert obj is my_object

关于python - pickle Cython 修饰函数导致 PicklingError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53776530/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com