diff --git a/_test.pyx b/_test.pyx index dfa25f0..b1536db 100644 --- a/_test.pyx +++ b/_test.pyx @@ -57,6 +57,8 @@ def test_the_wrapped_class(): T = PyTestClass() T.x = 15 print(T.x) + print("Is -10 positive?") + print(T.IsPositive(-10)) T = None diff --git a/pytestclass.pyx b/pytestclass.pyx index 4f0ddb9..1502fee 100644 --- a/pytestclass.pyx +++ b/pytestclass.pyx @@ -5,10 +5,9 @@ from testclass cimport TestClass - cdef class PyTestClass: - """ + """ Cython wrapper class for C++ class TestClass """ @@ -17,23 +16,23 @@ cdef class PyTestClass: def __cinit__(PyTestClass self): # Initialize the "this pointer" to NULL so __dealloc__ - # knows if there is something to deallocate. Do not + # knows if there is something to deallocate. Do not # call new TestClass() here. self._thisptr = NULL - + def __init__(PyTestClass self): # Constructing the C++ object might raise std::bad_alloc # which is automatically converted to a Python MemoryError # by Cython. We therefore need to call "new TestClass()" in # __init__ instead of __cinit__. - self._thisptr = new TestClass() + self._thisptr = new TestClass() def __dealloc__(PyTestClass self): - # Only call del if the C++ object is alive, + # Only call del if the C++ object is alive, # or we will get a segfault. if self._thisptr != NULL: del self._thisptr - + cdef int _check_alive(PyTestClass self) except -1: # Beacuse of the context manager protocol, the C++ object # might die before PyTestClass self is reclaimed. @@ -42,54 +41,54 @@ cdef class PyTestClass: if self._thisptr == NULL: raise RuntimeError("Wrapped C++ object is deleted") else: - return 0 + return 0 property x: - + # Here we use a property to expose the public member # x of TestClass to Python - + def __get__(PyTestClass self): self._check_alive() return self._thisptr.x - + def __set__(PyTestClass self, value): self._check_alive() self._thisptr.x = value property y: - + # Here we use a property to expose the public member # y of TestClass to Python - + def __get__(PyTestClass self): self._check_alive() return self._thisptr.y - + def __set__(PyTestClass self, value): self._check_alive() self._thisptr.y = value - - + + def Multiply(PyTestClass self, int a, int b): self._check_alive() return self._thisptr.Multiply(a,b) - - + + def IsPositive(PyTestClass self, int a): + self._check_alive() + return self._thisptr.IsPositive(a) + # The context manager protocol allows us to precisely # control the liftetime of the wrapped C++ object. del - # is called deterministically and independently of + # is called deterministically and independently of # the Python garbage collection. def __enter__(PyTestClass self): self._check_alive() return self - + def __exit__(PyTestClass self, exc_tp, exc_val, exc_tb): if self._thisptr != NULL: - del self._thisptr + del self._thisptr self._thisptr = NULL # inform __dealloc__ return False # propagate exceptions - - - diff --git a/testclass.h b/testclass.h index 2b4c80b..6228982 100644 --- a/testclass.h +++ b/testclass.h @@ -3,17 +3,18 @@ class TestClass { public: - + int x, y; - + TestClass(); - + virtual ~TestClass(); - + inline int Multiply(int a, int b){ return a*b; } + + inline bool IsPositive(int a){ return a>0;} }; #endif - diff --git a/testclass.pxd b/testclass.pxd index 033e64f..8184678 100644 --- a/testclass.pxd +++ b/testclass.pxd @@ -2,6 +2,7 @@ # Using a .pxd file gives us a separate namespace for # the C++ declarations. Using a .pxd file also allows # us to reuse the declaration in multiple .pyx modules. +from libcpp cimport bool as bool_t cdef extern from "testclass.h": @@ -9,8 +10,4 @@ cdef extern from "testclass.h": int x,y TestClass() except + # NB! std::bad_alloc will be converted to MemoryError int Multiply(int a, int b) - - - - - + bool_t IsPositive(int a)