I want to store C++ objects in a libcpp.map but I can't get it working. It even doesn't work on simple integers if I declare the map in the declarations file.
.pxd file:
from libcpp.map cimport map
cdef class MyClass:
cdef map[int,int] store
.pyx file:
cdef class MyClass:
def __cinit__(self):
self.store = map[int,int]()
Following error:
cdef map[int,int] store
^
C++ classes not allowed as members of an extension type,
use a pointer or reference instead
Why is this not working? If I declare it inside a function it's working fine.
going from the error it seems you need to store a pointer to it and invoke a new version on the heap
so
cdef map[int,int] *store
self.store = new map[int,int]()
Related
In the code below, self is a python object, as it is declared from def instead of cdef. Can a python object be referenced under a cdef function, just like how it is used under the c_function from my example below?
I am confused because cdef makes it sound like cdef is a C function, so I am not sure if it is able to take on a python object.
class A(self, int w):
def __init__():
self.a = w
cdef c_function (self, int b):
return self.a + b
Thank you,
I am the OP.
From "Cython: A Guide for Python Programmers":
Source: https://books.google.com.hk/books?id=H3JmBgAAQBAJ&pg=PA49&lpg=PA49&dq=python+object+cdef+function&source=bl&ots=QI9If_wiyR&sig=ACfU3U1CmEPBaEVmW0UN1_9m9G8B9a6oFQ&hl=en&sa=X&ved=2ahUKEwiBgs3Lw5vqAhXSZt4KHTs0DK0Q6AEwBHoECAoQAQ#v=onepage&q=python%20object%20cdef%20function&f=false
"[...] Nothing prevents us from declaring and using Python objects and dynamic variables in cdef functions, or accepting them as arguments"
So I take this as the book saying "yes" to my original question.
I am working on wrapping a C library using cython. I would like to use a cdef class to wrap a simple struct. The struct does require some parameters to be properly initialized. I put the corresponding code int the __cinit__ method like so:
cdef class Func:
cdef library.Func* func
def __cinit__(self, int value):
library.init_func(&self.func, value)
In python code I can create a function object via f = Func(17). The code then handles the initialization just fine. My question is the following: Say I want to extend the Func class in python (class MyFunc(Func): ...). How do I add a constructor to to MyFunc?
I would like to write a constructor with other parameters which calls
__cinit__(self, int value) with a value derived from constructor parameters. But it does not seem to be possible (likely for good reason) to call __cinit__ from python code.
Is there some way to include constructors in subclasses or should I create a wrapper around the function and delegate methods / properties?
I've been playing with Cython recently for the speed ups, but when I was trying to use copy.deepcopy() some error occurred.Here is the code:
from copy import deepcopy
cdef class cy_child:
cdef public:
int move[2]
int Q
int N
def __init__(self, move):
self.move = move
self.Q = 0
self.N = 0
a = cy_child((1,2))
b = deepcopy(a)
This is the error:
can't pickle _cython_magic_001970156a2636e3189b2b84ebe80443.cy_child objects
How can I solve the problem for this code?
As hpaulj says in the comments, deepcopy looks to use pickle by default to do its work. Cython cdef classes didn't used to be pickleable. In recent versions of Cython they are where possible (see also http://blog.behnel.de/posts/whats-new-in-cython-026.html) but pickling the array looks to be a problem (and even without the array I didn't get it to work).
The solution is to implement the relevant functions yourself. I've done __deepcopy__ since it's simple but alternatively you could implement the pickle protocol
def __deepcopy__(self,memo_dictionary):
res = cy_child(self.move)
res.Q = self.Q
res.N = self.N
return res
I suspect that you won't need to do that in the future as Cython improves their pickle implementation.
A note on memo_dictionary: Suppose you have
a=[None]
b=[A]
a[0]=B
# i.e. A contains a link to B and B contains a link to A
c = deepcopy(a)
memo_dictionary is used by deepcopy to keep a note of what it's already copied so that it doesn't loop forever. You don't need to do much with it yourself. However, if your cdef class contains a Python object (including another cdef class) you should copy it like this:
cdef class C:
cdef object o
def __deepcopy__(self,memo_dictionary):
# ...
res.o = deepcopy(self.o,memo_dictionary)
# ...
(i.e. make sure it gets passed on to further calls of deepcopy)
Using Cython to wrap some parts from a C++ API to python, I'm having misunderstandings that I couldn't fix by search similar questions. I like to access a Factory class that has the constructors private and a public method GetInstance.
namespace cpplibrary
{
class CppFactory
{
public:
static CppFactory& GetInstance();
private:
CppFactory(void);
CppFactory( const CppFactory& );
};
}
I'm trying a cython code like:
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
CppFactory() except +
CppFactory& GetInstance()
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = GetInstance()
I've check with as many variants as I thought. With and without the declaration of the constructor in the extern. With different ways to define the _thisptr from different posted examples. And so on. But I couldn't find a singleton example like this.
Where is the mistake I can't see?
I think you've got two issues:
1) How to wrap static methods: the recommended way is to declare the function outside the class, and use a string to tell Cython what name it should use in C++
2) The assignment to thisptr, where you just need to use & to get a pointer from the reference.
Code:
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
CppFactory() except +
# declare outside the class and use a string to specify name
# unfortunately this doesn't seem to play well with namespace
# so we need to specify it again
cdef CppFactory& CppFactory_GetInstance "cpplibrary::CppFactory::GetInstance"()
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = &CppFactory_GetInstance()
One of the problem is indeed to wrap a static method (here Getinstance()).
You can do that by using the cython #staticmethod decorator (see Cython's doc here):
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
#staticmember
CppFactory& GetInstance()
Then, the .pyx can be:
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = new CppFactory()
I've got a C library that I'm trying to wrap in Cython. One of the classes I'm creating contains a pointer to a C structure. I'd like to write a copy constructor that would create a second Python object pointing to the same C structure, but I'm having trouble, as the pointer cannot be converted into a python object.
Here's a sketch of what I'd like to have:
cdef class StructName:
cdef c_libname.StructName* __structname
def __cinit__(self, other = None):
if not other:
self.__structname = c_libname.constructStructName()
elif type(other) is StructName:
self.__structname = other.__structname
The real problem is that last line - it seems Cython can't access cdef fields from within a python method. I've tried writing an accessor method, with the same result. How can I create a copy constructor in this situation?
When playing with cdef classes, attribute access are compiled to C struct member access. As a consequence, to access to a cdef member of an object A you have to be sure of the type of A. In __cinit__ you didn't tell Cython that other is an instance of StructName. Therefore Cython refuses to compile other.__structname. To fix the problem, just write
def __cinit__(self, StructName other = None):
Note: None is equivalent to NULL and therefore is accepted as a StructName.
If you want more polymorphism then you have to rely on type casts:
def __cinit__(self, other = None):
cdef StructName ostr
if not other:
self.__structname = c_libname.constructStructName()
elif type(other) is StructName:
ostr = <StructName> other
self.__structname = ostr.__structname