【发布时间】:2019-03-24 22:16:14
【问题描述】:
尝试学习一点 Cython,我一直在尝试编写一个仅包含几个 cstrings 的玩具库(对应于因子/分类数据类型的可用选择)。类中指向的字符串被覆盖,而我的 C/Cython-foo 太小,无法弄清楚原因。
结果是这样的:
>>> import coupla
>>> ff = coupla.CouplaStrings(["one", "two"])
>>> ff
write, two
>>> ff
, two
>>> ff
two, two
非常感谢您的帮助!我觉得我快疯了。仅使用 to_cstring_array 和 to_str_list 函数似乎可以正常工作,但在类中它会失败。
cdef extern from "Python.h":
char* PyUnicode_AsUTF8(object unicode)
from libc.stdlib cimport malloc, free
cdef char **to_cstring_array(list_str):
"""Stolen from Stackoverflow:
https://stackoverflow.com/questions/17511309/fast-string-array-cython/17511714#17511714
"""
cdef Py_ssize_t num_strs = len(list_str)
cdef char **ret = <char **>malloc(num_strs * sizeof(char *))
for i in range(num_strs):
ret[i] = PyUnicode_AsUTF8(list_str[i])
return ret
cdef to_str_list(char **cstr_array, Py_ssize_t size):
cdef int i
result = []
for i in range(size):
result.append(bytes(cstr_array[i]).decode("utf-8"))
return result
cdef class CouplaStrings:
cdef char **_strings
cdef Py_ssize_t _num_strings
def __init__(self, strings):
cdef Py_ssize_t num_strings = len(strings)
cdef char **tstrings = <char **> to_cstring_array(strings)
self._num_strings = num_strings
self._strings = tstrings
def __repr__(self):
"""Just for testing."""
return ", ".join(to_str_list(self._strings, self._num_strings))
def __dealloc__(self):
free(self._strings)
编辑:
请参阅下面 user2357112 的答案。 CouplaStrings 的编辑版本似乎避免了这个特定的问题,尽管我不会发誓它的整体正确性。
编辑 2:这是错误的,请忽略仅出于历史目的而保留
cdef class CouplaStrings:
cdef char **_strings
cdef Py_ssize_t _num_strings
def __init__(self, strings):
cdef Py_ssize_t num_strings = len(strings)
cdef char **ret = <char **> PyMem_Malloc(num_strings * sizeof(char *))
for i in range(num_strings):
ret[i] = <char *> PyMem_Realloc(PyUnicode_AsUTF8(strings[i]),
sizeof(char *))
self._num_strings = num_strings
self._strings = ret
def __repr__(self):
"""Just for testing."""
return ", ".join(to_str_list(self._strings, self._num_strings))
def __dealloc__(self):
PyMem_Free(self._strings)
【问题讨论】:
-
编辑后的版本更差!你已经重新分配了 Python 认为它正在管理的内存。你想计算出大小,malloc一个新的但内存,然后复制。或者只是避免使用 C 字符串,因为它们总是很痛苦。
-
哦不!好吧,我想这并不奇怪。回到这里的绘图板。