📜  Python|在数组上操作的扩展函数

📅  最后修改于: 2022-05-13 01:54:49.579000             🧑  作者: Mango

Python|在数组上操作的扩展函数

让我们编写一个 C 扩展函数,它可以对连续的数据数组进行操作,这可能是由数组模块或 NumPy 等库创建的,这个函数应该是通用的,而不是特定于任何一个数组库。

代码应使用缓冲区协议以可移植的方式接收和处理数组。下面的代码是一个 C 扩展函数,它接收数组数据并调用本文中的avg(double *buf, int len)函数——在Python中使用 C 代码。

代码#1:

/* Call double avg(double *, int) */
static PyObject *py_avg(PyObject *self, PyObject *args)
{
    PyObject *bufobj;
    Py_buffer view;
    double result;
    /* Get the passed Python object */
    if (!PyArg_ParseTuple(args, "O", &bufobj))
    {
        return NULL;
    }
  
    /* Attempt to extract buffer information from it */
  
    if (PyObject_GetBuffer(bufobj, &view,
                           PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT) == -1)
    {
        return NULL;
    }
  
    if (view.ndim != 1)
    {
        PyErr_SetString(PyExc_TypeError, "Expected a 1-dimensional array");
        PyBuffer_Release(&view);
        return NULL;
    }
  
    /* Check the type of items in the array */
    if (strcmp(view.format, "d") != 0)
    {
        PyErr_SetString(PyExc_TypeError, "Expected an array of doubles");
        PyBuffer_Release(&view);
        return NULL;
    }
  
    /* Pass the raw buffer and size to the C function */
    result = avg(view.buf, view.shape[0]);
  
    /* Indicate we're done working with the buffer */
    PyBuffer_Release(&view);
    return Py_BuildValue("d", result);
}

代码#2:这个扩展函数是如何工作的

import array
  
print("Average : ", avg(array.array('d', [1, 2, 3])))
  
import numpy
print("Average numpy array : ", avg(numpy.array([1.0, 2.0, 3.0])))
print ("Average list : \n", avg([1, 2, 3]))

输出 :

Average : 2.0

Average numpy array : 2.0
Average list : 
Traceback (most recent call last):
File "", line 1, in 
TypeError: 'list' does not support the buffer interface
  • PyBuffer_GetBuffer()函数是文中代码的关键。
  • 它尝试获取有关给定任意Python对象中的内存表示的信息。
  • 如果无法获取信息(与普通Python对象一样),它只会引发异常并返回 -1。
  • 传递给PyBuffer_GetBuffer()的特殊标志提供了有关请求的内存缓冲区类型的额外提示。
  • 因为, PyBUF_ANY_CONTIGUOUS指定需要一个连续的内存区域。