I've been playing with Cython recently for the speed ups, but my project inherits a module that has a copy()
method which uses deepcopy()
. I tried implementing the deepcopy()
within an overrided version of copy()
, and I thought I had it working, but it doesn't appear to be anymore.
TypeError: object.__new__(cython_binding_builtin_function_or_method) is not safe,
use cython_binding_builtin_function_or_method.__new__()
This is occuring in python/lib/copy_reg.py here:
return cls.__new__(cls, *args)
I'm on Python 2.7 here. Is it possible that a newer version of Python returns from deepcopy()
in a "safe" way? I'm also on the latest version of Cython, 0.15.1.
Note that I've removed the previous updates to keep this as simple as possible.
Ok! I think I found the incompatibility but I don't really know what to do about it.
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}
Then in my main app:
from cython1 import CythonClass
from copy import deepcopy
if __name__ == "__main__":
gc1 = CythonClass()
gc1.call_handle()
gc2 = deepcopy(gc1)
I get:
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__()
The key is the function/handle reference:
handles = {"handle_method", handle_method}
If I don't include the method/function reference, Cython will not blow up during deepcopy. If I include one, it doesn't like how deepcopy/copy_reg copies the reference over.
Any ideas besides not using method/function references? I have a bit of untangling to do if that the simple answer. (which I'm already working on as I finish typing this)
Thanks!
copy() create reference to original object. If you change copied object - you change the original object. . deepcopy() creates new object and does real copying of original object to new one. Changing new deepcopied object doesn't affect original object.
A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
To make a deep copy, use the deepcopy() function of the copy module. In a deep copy, copies are inserted instead of references to objects, so changing one does not change the other.
Copy an Object in Python In Python, we use = operator to create a copy of an object. You may think that this creates a new object; it doesn't. It only creates a new variable that shares the reference of the original object.
found this:
"Does deepcopy work properly with Cython?"
No. In this case (you are using extension types, i.e cdef classes) you have to implement the pickle protocol for your class http://docs.python.org/library/pickle.html#pickling-and-unpickling-extension-types
from here: https://groups.google.com/forum/#!topic/cython-users/p2mzJrnOH4Q
"implementing the pickle protocol" in the linked article is actually simple, and solved my problems trivially (although I am doing things slightly differently - my class is a cdef class
, and I have a pointer to a CPP object stored there which cannot be trivially duplicated - I don't know if this will solve the python-inheritance problem above, but it is certainly worth a try.)
Anyway, implementing the pickle protocol is trivial (the example below is using "C++ cython", which has a double meaning for the del
keyword, 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))
When I try this, I can call copy.deepcopy()
on a dict containing an instance of my Cython extension type, and get a new dictionary containing a new instance (with a different memory address when printed to terminal.) Previously the same code caused a segfault.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With