我们可以在 Cython 中创建 Python 对象的 C 数组吗?
让我们考虑以下代码:
class C:
pass
cdef object f():
return C()
cdef void g(unsigned n):
cdef object obj0 = f()
cdef object obj1 = f()
cdef object obj2 = f()
cdef object obj3 = f()
有没有一种方法可以将各种对象存储在一个数组中,而不是使用多个变量?类似的东西:
cdef void g(unsigned n):
cdef object[N_MAX] obj
for i in range(n)
obj[i] = f()
实际上不可能创建一个
object
的数组。一个警告是,如果可以的话,我们应该使用 Py_INCREf
/Py_DECREF
手动管理对象的生命周期。
最简单和最安全的举动可能是在 Python 层维护对象列表。按照原始问题中给出的示例,例如,我们可以使用列表理解:
cdef void g(unsigned n):
l = [f() for _ in range(n)]
#...
这被编译成以下内容:
__pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __pyx_v_n;
for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
__pyx_v__ = __pyx_t_3;
__pyx_t_4 = __pyx_f_1a_f(); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_4))) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__pyx_v_l = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
我很想使用 PyList_New 和 PyList_SET_ITEM 手动管理列表,以避免连续调用
__Pyx_ListComp_Append
:
from cpython cimport PyList_New, PyList_SET_ITEM, Py_INCREF
cdef void h(unsigned n):
cdef object l = PyList_New(n)
cdef unsigned i
for i in range(n):
o = f()
Py_INCREF(o)
PyList_SET_ITEM(l, i, o)
#...
在实践中,这会大大降低代码的可读性(并且更容易出错),而好处微乎其微。