#ifndef CLASS_A
#define CLASS_A
#include "b.h"
class A {
public:
A() {}
B* getB();
};
#endif#include "a.h"
B * A::getB() { return new B; }#ifndef CLASS_B
#define CLASS_B
class B {
public:
B() {}
void nop() const;
};
#endif
#include "b.h"
#include <cstdio>
void B::nop() const
{
std::printf("My address is %p\n", this);
}
from class_b cimport _B
cdef extern from "a.h":
cdef cppclass _A "A":
_A() except +
_B * getB()from class_b cimport _B
cdef class A:
cdef _A c_obj
def __cinit__(self):
self.c_obj = _A()
def getB(self):
_b = self.c_obj.getB()
b = B(*_b)
return bcdef extern from "b.h":
cdef cppclass _B "B":
_B() except +
void nop()cdef class B:
cdef _B c_obj
def __cinit__(self, _B _Object=None):
if _B is None:
self.c_obj = _B()
else:
self.c_obj = _Object
def nop(self):
self.c_obj.nop()
from distutils.core import setup, Extension
from Cython.Build import cythonize
modules = [
Extension(
"class_a",
sources = [ "class_a.pyx" ],
language = "c++",
library_dirs = [ "." ],
libraries = [ "class" ],
),
Extension(
"class_b",
sources = [ "class_b.pyx" ],
language = "c++",
library_dirs = [ "." ],
libraries = [ "class" ],
),
]
setup(
name="pyClass",
package_dir={'' : ''},
ext_modules=cythonize(modules, build_dir="./")
) g++ -fPIC -o class_a.o a.cpp -c
g++ -fPIC -o class_b.o b.cpp -c
g++ -shared -Wl,-soname,libclass.so -o libclass.so class_a.o class_b.o
python setup.py build_ext installCompiling class_a.pyx because it changed.
Compiling class_b.pyx because it changed.
[1/2] Cythonizing class_a.pyx
Error compiling Cython file:
------------------------------------------------------------
...
def __cinit__(self):
self.c_obj = _A()
def getB(self):
_b = self.c_obj.getB()
b = B(*_b)
^
------------------------------------------------------------
class_a.pyx:10:12: undeclared name not builtin: B
Error compiling Cython file:
------------------------------------------------------------
...
def __cinit__(self):
self.c_obj = _A()
def getB(self):
_b = self.c_obj.getB()
b = B(*_b)
^
------------------------------------------------------------
class_a.pyx:10:15: Cannot convert '_B *' to Python object
>> def getB(self):
>> _b = self.c_obj.getB()
>> b = B(*_b)
>> ^
>> ------------------------------------------------------------
>>
>> class_a.pyx:10:12: undeclared name not builtin: B
This is because you import the class as _B and are trying to invoke it as B.
__init__ (and, consequently) __cinit__ methods cannot take non-Python
arguments. The typical solution to this is to add a static create
method that can take such arguments. E.g.
cdef class B(object):
cdef B* c_obj
@staticmethod
cdef B create(B* ptr):
cdef B result = B()
result.c_obj = ptr
return result