我最近一直在玩Cython加速游戏,但我的项目继承了一个模块,该模块具有使用deepcopy()
的copy()
方法。我尝试在copy()
的过度版本中实现deepcopy()
,我认为它已经工作了,但它似乎不再工作了。
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。
更新3
请注意,我已经删除了以前的更新,以使其尽可能简单
好的!我想我发现了不兼容,但我真的不知道该怎么办。
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:python26libcopy.py", line 162, in deepcopy
y = copier(x, memo)
File "C:python26libcopy.py", line 292, in _deepcopy_inst
state = deepcopy(state, memo)
File "C:python26libcopy.py", line 162, in deepcopy
y = copier(x, memo)
File "C:python26libcopy.py", line 255, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "C:python26libcopy.py", line 189, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "C:python26libcopy.py", line 323, in _reconstruct
y = callable(*args)
File "C:python26libcopy_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复制引用的方式。
除了不使用方法/函数引用之外,还有什么想法吗?如果这是一个简单的答案的话,我还有一些事情要做。(当我完成打字时,我已经在处理了(
谢谢!
发现:
"深度复制与Cython一起正常工作吗?">
没有。在这种情况下(您使用的是扩展类型,即cdef类(必须为您的类实现pickle协议http://docs.python.org/library/pickle.html#pickling-和取消拾取扩展类型
从这里:https://groups.google.com/forum/#!主题/cython用户/p2mzJrnOH4Q
链接文章中的"实现pickle协议"实际上很简单,很简单地解决了我的问题(尽管我做的事情略有不同——我的类是cdef class
,我有一个指向CPP对象的指针存储在那里,不能简单地复制——我不知道这是否能解决上面的python继承问题,但它肯定值得一试。(
无论如何,实现pickle协议是微不足道的(下面的例子是使用"C++cython",它对del
关键字有双重含义。(:
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()
,并获得一个包含新实例的新字典(打印到终端时具有不同的内存地址(。以前,相同的代码会导致segfault。
啊,终于找到了"回答自己的问题"按钮。
我可能很不耐烦,但由于还没有人回复(我的意思是谁在使用Cython并在周四下午回答问题(,我想我会结束这一次。
1( Cython不喜欢对具有函数/方法引用变量的类执行深度复制。那些变量副本将失败。据我所知,没有什么可以解决的,你只需要想出一个不需要它们的新设计。我最终使用了上面和我的项目中相同的代码。
2( Cython根本不处理属性修饰符。你不能@property
和@<property name>.setter
。房地产需要按照旧的方式设置。例如CCD_ 11。
3( 继承的非Cython类的方法"可能"不可访问。我知道这很模糊。我不能完全解释。我要说的是,我继承了NetworkX.DiGraph
,而number_of_nodes()
在Cython之后是不可访问的,当时它是直Python。我必须创建一个对该方法的引用并使用它。例如number_of_verts = NetworkX.DiGraph.number_of_nodes
。