I have classes nested in classes and inside of a namespace in c++ in the following format:
namespace my_Namespace{
class MyFirstClass{
class NestedClass{
public:
NestedClass(int arg){};
NestedClass(double arg{};
NestedClass(std::string arg){};
};
};
};
And from the documentation you import the classes in cython like so:
cdef extern from "myfile.hpp" namespace "my_Namespace":
cdef cppclass MyFirstClass "my_Namespace::MyFirstClass"
cdef cppclass NestedClass "my_Namespace::MyFirstClass::NestedClass`
Side note, do we need any imports for the cython script to use cppclass? Im not seeing it as a keyword.
Anyway, since NestedClass
has constructor overload how would I implement each in cython? I am trying to do this so that it can be normally imported in python, am I better off just making the whole c++ namespace and functions and putting them in a DLL and just use ctypes
to import and use the functions?
And one last question I am seeing the documents create classes from the cython code above like so:
cdef class NestedClass:
cdef NestedClass* obj_
def __cinit__(self):
self.obj_=new NestedClass()
def __dealloc__(self): del self.obj_
Is this correct and can I just use the NestClass
that I got from the C++ file to derive classes like so:
`cdef class NestedClassInt:
cdef NestedClass* obj_
def __cinit__(self,arg:int): self.obj_=new NestedClass(arg)
#Now define the define the string one
def class NestedClassString:
cdef NestedClass* obj_
def __cinit__(self,arg:str): self.obj_=new NestedClass(arg)
I have been reading multiple forums and I know that python does not support constructor overloading so I don't see if Cython does or if there is a way to convert from it.
The upshot as I explained in the comments is that you can declare the overloads for your C++ methods and Cython understands them. You can't declare overloads for methods of cdef classes, and therefore need to pick some other way of switching based on type.
I suggested either using different factory functions (classmethods/staticmethods) or using isinstance
in __init__
.
# distutils: language = c++
from libcpp.string cimport string as std_string
cdef extern from * namespace "my_Namespace":
"""
namespace my_Namespace{
class MyFirstClass{
public:
class NestedClass{
public:
NestedClass(int arg){};
NestedClass(double arg){};
NestedClass(std::string arg){};
};
};
};
"""
cdef cppclass MyFirstClass:
cppclass NestedClass:
NestedClass(int arg)
NestedClass(double arg)
NestedClass(std_string arg)
cdef class NestedClassWrapper:
cdef MyFirstClass.NestedClass* nc
def __dealloc__(self):
del self.nc
@classmethod # use staticmethod to make this cdef
def make_from_int(cls, int arg):
cdef NestedClassWrapper o = cls.__new__(cls)
o.nc = new MyFirstClass.NestedClass(arg)
return o
# and the same pattern for the int and string versions
cdef class NestedClassWrapper2:
cdef MyFirstClass.NestedClass* nc
def __dealloc__(self):
del self.nc
def __cinit__(self, arg):
if isinstance(arg, int):
# cast to a C int
self.nc = new MyFirstClass.NestedClass(<int>arg)
elif isinstance(arg, float):
self.nc = new MyFirstClass.NestedClass(<double>arg)
elif isinstance(arg, bytes):
self.nc = new MyFirstClass.NestedClass(<std_string>arg)
else:
raise TypeError
Other variations on the theme might also exist. For example a fused type as an argument to __cinit__
, or using try: ... except
to test the type conversions rather than isinstance
. But most solutions will look something like one of these two approaches.
cppclass
should be recognised providing you name the file .pyx
. It may not be highlighted by your editor though.