Cython和deepcopy()使用引用的方法/函数陷入困境.任何其他想法



我最近一直在玩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

最新更新