Consider the following contrived Cython function to join a list of strings:
# cython: language_level=3
cpdef test_join():
""" ["abc", "def", "ghi"] -> "abcdefghi" """
cdef:
list lines = ["abc", "def", "ghi"]
char* out = ""
char* line = ""
int i
for i in range(len(lines)):
line = lines[i]
out = out + line
return out
It will fail to compile, with this error:
Storing unsafe C derivative of temporary Python reference
I am assuming this has to do with line
being of type char*
and continually re-assigned. I have seen an answer to a similar question, but haven't been able to modify that answer for this basic example. (And it also involves a good amount of C-API with which I'm not familiar.)
How can I modify the above function to compile and return as expected?
More broadly, I want to better understand this error. Commit 37e4a20 has a bit of explanation:
Taking a
char*
from a temporary Python string object ... A compile time error is raised only when such a pointer is assigned to a variable and would thus exceed the lifetime of the string itself.
Update: to simplify things a bit further, it looks like it's the assignment that causes the issue:
cpdef int will_succeed():
cdef char* a = b"hello"
cdef char* b = b" world"
print(a + b) # no new assignment
return 1
cpdef will_fail():
cdef char* a = b"hello"
cdef char* b = b" world"
a = a + b # won't compile
return a
I suspect there may be a more proper way do this this with something from string.pxd
/string.h
, but I'm pretty weak on C memory management and efficiency:
from libc.string cimport strcat, strcpy
cpdef use_strcat():
cdef char out[1024]
strcpy(out, b"")
cdef char* a = b"hello"
cdef char* b = b" world"
strcat(out, a)
strcat(out, b)
return out