When I cythonize the following Cython-module
%%cython
cdef double *ptr=[1,2,3]
print(ptr)
I get the following error message:
Cannot convert 'double *' to Python object
However, the following Cython module:
%%cython
cdef double val=0.0
print(val)
is cythonized without problems.
This problem occurs also for any other pointer type (i.e. int *
, float *
and so on).
print
is a pure Python function and in order to be able to call it, the arguments must be Python objects.
Obviously, neither ptr
in the first Cython-module nor val
in the second are python objects. There is however a difference: a cdef
variable of type double
can be converted to a Python-Float automaticly by Cython via PyFloat_FromDouble
- and this is exactly what happens under the hood: Cython creates a temporary Python-Float from val
, passes it to print
and destroys it afterwards.
There are other types which can be automatically converted to Python objects: double
, float
, int
& similar, but also std::vector
and other c++-containers.
However, there is no such automatic conversion for raw-C-pointers (char *
, Py_UNICODE*
and their different reincarnations being an exception - see the example later on) - because it is not possible to do in the first place, as Cython doesn't know the length of the array (is it an array at all?) to which the pointer points.
The only solution in this case: one has to manually convert the content of the memory to a python list (or to whatever python-type it corresponds), here as example the function convert_to_python
:
%%cython
cdef convert_to_python(double *ptr, int n):
cdef int i
lst=[]
for i in range(n):
lst.append(ptr[i])
return lst
cdef double *ptr=[1,2,3]
print(convert_to_python(ptr,3))
The most noteworthy thing is, that convert_to_python
gets the number of elements as parameter - the information Cython is missing.
Btw: Cython would automatically convert C-arrays with known length to Python objects, for example:
%%cython
cdef double arr[3] # length (=3) known to Cython
arr[:]=[1,2,3]
print(arr)
compiles without problems.
char *
, signed char *
, unsigned char *
, Py_UNICODE *
and their const
-variants are "special", because they can be automatically converted to either a bytes
-object (char *
) or unicode
-object (Py_UNICODE *
), assuming it is a null-terminated C-string (i.e. character \0
marks the end). Thus, it is possible to write code similar to
cdef char a[3]
a = [90,0,90] # ord('Z') = 90
print(a) # char[3] decays to char *
# b"Z"
As one can see, the result is not b"Z\x00Z", because the string get automatically truncated at first `\0'. To ensure that the whole string converted to bytes object one has to specify length:
print(a[:3])
# b"Z\x00Z"
However, problem can arise if there is no \0
in the char-array, which could lead to segfaults (reads out of bounds).
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