我最近一直在玩Cython以加快速度,但我的项目继承了一个使用copy()
deepcopy()
方法的模块。我尝试在deepcopy()
的覆盖版本中实现copy()
,我认为我已经有了它,但它似乎不再存在了。
TypeError: object.__new__(cython_binding_builtin_function_or_method) is not safe,
use cython_binding_builtin_function_or_method.__new__()
这是在python / lib / copy_reg.py中发生的:
return cls.__new__(cls, *args)
我在这里使用Python 2.7。新版本的Python是否有可能以“安全”的方式从deepcopy()
返回?我也是最新版的Cython,0.15.1。
请注意,我已删除了之前的更新,以使其尽可能简单。
确定!我想我发现了不兼容性,但我真的不知道该怎么办。
class CythonClass:
def __init__(self):
self._handle = self._handles.get("handle_method")
def call_handle(self):
self._handle(self)
def handle_method(self):
print "I'm a little handle!"
handles = {"handle_method", handle_method}
然后在我的主应用程序中:
from cython1 import CythonClass
from copy import deepcopy
if __name__ == "__main__":
gc1 = CythonClass()
gc1.call_handle()
gc2 = deepcopy(gc1)
我明白了:
I'm a little handle!
Traceback (most recent call last):
File "cythontest.py", line 8, in <module>
gc2 = deepcopy(gc1)
File "C:\python26\lib\copy.py", line 162, in deepcopy
y = copier(x, memo)
File "C:\python26\lib\copy.py", line 292, in _deepcopy_inst
state = deepcopy(state, memo)
File "C:\python26\lib\copy.py", line 162, in deepcopy
y = copier(x, memo)
File "C:\python26\lib\copy.py", line 255, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "C:\python26\lib\copy.py", line 189, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "C:\python26\lib\copy.py", line 323, in _reconstruct
y = callable(*args)
File "C:\python26\lib\copy_reg.py", line 93, in __newobj__
return cls.__new__(cls, *args)
TypeError: object.__new__(cython_binding_builtin_function_or_method) is not safe, use cython_binding_builtin_function_or_method.__new__()
键是函数/句柄引用:
handles = {"handle_method", handle_method}
如果我不包含方法/函数引用,Cython在深度复制期间不会爆炸。如果我包含一个,它不喜欢deepcopy / copy_reg如何复制引用。
除了不使用方法/函数引用之外的任何想法?如果这个简单的答案,我有点想要做。 (当我完成输入时,我已经在努力了)
谢谢!
答案 0 :(得分:8)
我可能很不耐烦,但由于没有人回复(我的意思是谁在周四下午使用Cython并回答问题),我想我会关闭这个。
1)Cython不喜欢对具有函数/方法引用变量的类进行深度复制。那些变量副本将失败。从我所知,它没有解决它,你只需要想出一个不需要它们的新设计。我最终使用上面的相同代码和我的项目进行了这样做。
2)Cython根本不处理属性装饰器。您不能@property
和@<property name>.setter
。属性需要以旧时尚的方式设置。例如<property name> = property(get_property, set_property)
。
3)继承的非Cython类的方法“可能”无法访问。我知道这个含糊不清。我无法完全解释它。我要说的是,我继承了NetworkX.DiGraph
,而number_of_nodes()
在Cython之后无法访问,而它是直接的Python。我必须创建一个方法的引用并使用它。例如number_of_verts = NetworkX.DiGraph.number_of_nodes
。
答案 1 :(得分:7)
发现了这个:
“深度复制是否适用于Cython?”
号。在这种情况下(您正在使用扩展类型,即cdef类) 必须为你的班级实施泡菜协议 http://docs.python.org/library/pickle.html#pickling-and-unpickling-extension-types
从这里开始:https://groups.google.com/forum/#!topic/cython-users/p2mzJrnOH4Q
在链接文章中“实现pickle协议”实际上很简单,并且很容易解决我的问题(虽然我做的事情略有不同 - 我的类是cdef class
,我有一个指向CPP对象的指针存储在那里不能轻易复制 - 我不知道这是否会解决上面的python继承问题,但它肯定值得一试。)
无论如何,实现pickle协议是微不足道的(以下示例使用“C ++ cython”,它对del
关键字among other things具有双重含义。):
cdef class PyObject(object):
cdef CppObject* cpp
cdef object arg1
cdef object arg2
def __cinit__(self, arg1=[], arg2=False):
# C++ constructor using python values, store result in self.cpp.
# new code: cache the python arguments that were used.
self.arg1 = arg1
self.arg2 = arg2
def __init__(self, arg1=[], arg2=False):
# logic for validating arguments.
pass
def __dealloc__(self):
if not self.cpp == NULL:
del self.cpp
def __reduce__(self):
# a tuple as specified in the pickle docs - (class_or_constructor,
# (tuple, of, args, to, constructor))
return (self.__class__, (self.arg1, self.arg2))
当我尝试这个时,我可以在包含我的Cython扩展类型实例的dict上调用copy.deepcopy()
,并获得一个包含新实例的新字典(当打印到终端时具有不同的内存地址。)相同的代码导致了段错误。