为什么数组中的内存视图赋值有Python交互?

问题描述 投票:0回答:1

当使用

cython -a my-file.pyx
编译时,这一行简单的cdef在html文件中被注释为黄色。

# my-file.pyx
from cpython.array cimport array

def f(double[:] xyz):
    cdef double[:] inv2 = array('d', [xyz[0]*3, xyz[1], xyz[2]*3])

这是正确的吗?我本以为这条线没有 python 交互。

我实际上不知道如何判断代码除了 html 文件中的行的颜色之外是否仍然具有 python 交互。当线条呈黄色时,我如何判断是否还有需要改进的地方?

对应的c代码是

  __pyx_t_1 = 0;
  __pyx_t_2 = -1;
  if (__pyx_t_1 < 0) {
    __pyx_t_1 += __pyx_v_xyz.shape[0];
    if (unlikely(__pyx_t_1 < 0)) __pyx_t_2 = 0;
  } else if (unlikely(__pyx_t_1 >= __pyx_v_xyz.shape[0])) __pyx_t_2 = 0;
  if (unlikely(__pyx_t_2 != -1)) {
    __Pyx_RaiseBufferIndexError(__pyx_t_2);
    __PYX_ERR(0, 5, __pyx_L1_error)
  }
  __pyx_t_3 = PyFloat_FromDouble(((*((double *) ( /* dim=0 */ (__pyx_v_xyz.data + __pyx_t_1 * __pyx_v_xyz.strides[0]) ))) * 3.0)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_1 = 1;
  __pyx_t_2 = -1;
  if (__pyx_t_1 < 0) {
    __pyx_t_1 += __pyx_v_xyz.shape[0];
    if (unlikely(__pyx_t_1 < 0)) __pyx_t_2 = 0;
  } else if (unlikely(__pyx_t_1 >= __pyx_v_xyz.shape[0])) __pyx_t_2 = 0;
  if (unlikely(__pyx_t_2 != -1)) {
    __Pyx_RaiseBufferIndexError(__pyx_t_2);
    __PYX_ERR(0, 5, __pyx_L1_error)
  }
  __pyx_t_4 = PyFloat_FromDouble((*((double *) ( /* dim=0 */ (__pyx_v_xyz.data + __pyx_t_1 * __pyx_v_xyz.strides[0]) )))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_1 = 2;
  __pyx_t_2 = -1;
  if (__pyx_t_1 < 0) {
    __pyx_t_1 += __pyx_v_xyz.shape[0];
    if (unlikely(__pyx_t_1 < 0)) __pyx_t_2 = 0;
  } else if (unlikely(__pyx_t_1 >= __pyx_v_xyz.shape[0])) __pyx_t_2 = 0;
  if (unlikely(__pyx_t_2 != -1)) {
    __Pyx_RaiseBufferIndexError(__pyx_t_2);
    __PYX_ERR(0, 5, __pyx_L1_error)
  }
  __pyx_t_5 = PyFloat_FromDouble(((*((double *) ( /* dim=0 */ (__pyx_v_xyz.data + __pyx_t_1 * __pyx_v_xyz.strides[0]) ))) * 3.0)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_6 = PyList_New(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_GIVEREF(__pyx_t_3);
  PyList_SET_ITEM(__pyx_t_6, 0, __pyx_t_3);
  __Pyx_GIVEREF(__pyx_t_4);
  PyList_SET_ITEM(__pyx_t_6, 1, __pyx_t_4);
  __Pyx_GIVEREF(__pyx_t_5);
  PyList_SET_ITEM(__pyx_t_6, 2, __pyx_t_5);
  __pyx_t_3 = 0;
  __pyx_t_4 = 0;
  __pyx_t_5 = 0;
  __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_INCREF(__pyx_n_s_d);
  __Pyx_GIVEREF(__pyx_n_s_d);
  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_n_s_d);
  __Pyx_GIVEREF(__pyx_t_6);
  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_6);
  __pyx_t_6 = 0;
  __pyx_t_6 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_7cpython_5array_array), __pyx_t_5, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_ds_double(__pyx_t_6, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_v_inv2 = __pyx_t_7;
  __pyx_t_7.memview = NULL;
  __pyx_t_7.data = NULL;`
python arrays cython memoryview
1个回答
0
投票

内存视图只是一种访问支持缓冲区协议的 Python 对象数据的有效方法(实际优化的部分是索引)。

cpython.array
只是一个支持缓冲区协议的Python对象。

所以这条线

cdef double[:] inv2 = array('d', [xyz[0]*3, xyz[1], xyz[2]*3])

需要:

  1. 使用参数
    'd'
    (Python 字符串)和一个三长值列表调用 Python 函数。 Cython 对
    array.array
    有一点特殊的可见性,但不是太多。
  2. 检查返回的Python对象是否支持double类型的缓冲协议。
  3. 进行一些引用计数,以便 Python 对象的生命周期至少与内存视图的生命周期一样长。

我认为没有一种快速方法可以创建一个空的

array.array
而不需要一堆Python对象,但我认为理想情况下你应该创建一个空数组,然后填充元素。

# Numpy just as an illustrative example
cdef double[:] inv2 = np.empty((3,), dtype=np.double)
inv2[0] = xyz[0]*3
inv2[1] = xyz[1]
inv2[2] = xyz[2]*3

这样,所有的数学运算都保存在 C 中(但对

np.empty
的调用仍然是 Python 调用,对于 3 长数组来说,最终可能会产生比现在更多的开销)。

© www.soinside.com 2019 - 2024. All rights reserved.