ufunc API#

常量#

`` UFUNC_{THING}_{ERR} ``

已弃用,请改用 `` NPY_{THING}_{ERR} ``

UFUNC_FPE_DIVIDEBYZERO#
UFUNC_FPE_OVERFLOW#
UFUNC_FPE_UNDERFLOW#
UFUNC_FPE_INVALID#
`` PyUFunc_{VALUE} ``
PyUFunc_One#
PyUFunc_Zero#
PyUFunc_MinusOne#
PyUFunc_ReorderableNone#
PyUFunc_None#
PyUFunc_IdentityValue#

#

NPY_LOOP_BEGIN_THREADS#

在通用函数代码中使用,仅当 loop->obj 不为 true 时才释放 Python GIL(即,这不是 OBJECT 数组循环).需要在变量声明区域中使用 NPY_BEGIN_THREADS_DEF .

NPY_LOOP_END_THREADS#

在通用函数代码中使用,如果 Python GIL 已释放(因为 loop->obj 不为 true),则重新获取 Python GIL.

类型#

type PyUFuncGenericFunction#

指向实际实现底层(逐个元素)函数 \(N\) 次的函数的指针,具有以下签名:

void loopfunc(char **args, npy_intp const *dimensions, npy_intp const *steps, void *data)#
参数:
  • args – 指向输入和输出数组的实际数据的指针数组.输入参数首先给出,然后是输出参数.

  • dimensions – 指向此函数正在循环的维度大小的指针.

  • steps – 指向字节数的指针,该字节数用于跳转以获取此维度中每个输入和输出参数的下一个元素.

  • data – 可以与 ufunc 一起存储并在调用时传入的任意数据(额外参数,函数名称等).可以为 NULL . .. versionchanged:: 1.23.0 除了 NULL 值数组之外,还接受 NULL data .

这是一个专门用于加法运算并且返回双精度浮点数的函数示例.

static void
double_add(char **args,
           npy_intp const *dimensions,
           npy_intp const *steps,
           void *extra)
{
    npy_intp i;
    npy_intp is1 = steps[0], is2 = steps[1];
    npy_intp os = steps[2], n = dimensions[0];
    char *i1 = args[0], *i2 = args[1], *op = args[2];
    for (i = 0; i < n; i++) {
        *((double *)op) = *((double *)i1) +
                          *((double *)i2);
        i1 += is1;
        i2 += is2;
        op += os;
     }
}

函数#

PyObject *PyUFunc_FromFuncAndData(PyUFuncGenericFunction *func, void *const *data, const char *types, int ntypes, int nin, int nout, int identity, const char *name, const char *doc, int unused)#

从所需的变量创建一个新的广播通用函数.每个ufunc都围绕着逐元素操作的概念构建.每个ufunc对象都包含指向1-d循环的指针,这些循环实现了每种支持类型的基本功能.

备注

PyUFunc_FromFuncAndData 不会复制 func,data,types,name 和 doc 参数.调用者必须确保只要 ufunc 对象存在,就不会释放这些数组使用的内存.

参数:
  • func – 必须指向包含 ntypes 个 PyUFuncGenericFunction 元素的数组.

  • data – 应该是 NULL 或指向大小为 ntypes 的数组的指针.该数组可能包含任意的额外数据,这些数据将传递给 func 数组中的相应循环函数,包括 NULL .

  • types – 长度为 (nin + nout) * ntypeschar 数组,编码了 func 数组中相应函数接受的 numpy.dtype.num (仅限内置)类型.例如,对于具有三个 ntypes ,两个 nin 和一个 nout 的比较 ufunc,其中第一个函数接受 numpy.int32 ,第二个函数接受 numpy.int64 ,两者都返回 numpy.bool_ ,则 types 将是 (char[]) {5, 5, 0, 7, 7, 0} ,因为 NPY_INT32 是 5, NPY_INT64 是 7,而 NPY_BOOL 是 0.如果需要,也可以使用位宽名称 (例如: NPY_INT32 , NPY_COMPLEX128 ). 类型转换规则 将在运行时用于查找输入/输出提供的第一个可调用的 func .

  • ntypes – ufunc实现的不同的数据类型特定的函数的数量.

  • nin – 此操作的输入数量.

  • nout – 输出的数量.

  • identity – 可以是 PyUFunc_One , PyUFunc_Zero , PyUFunc_MinusOnePyUFunc_None 之一.这指定了当将空数组传递给 ufunc 的 reduce 方法时应返回什么.特殊值 PyUFunc_IdentityValue 只能与 PyUFunc_FromFuncAndDataAndSignatureAndIdentity 方法一起使用,以允许将任意 python 对象用作 identity.

  • name – 作为 NULL 终止字符串的 ufunc 的名称.指定 ‘add’ 或 ‘multiply’ 名称会为整数类型的缩减启用特殊行为,此时不提供 dtype.如果输入类型是小于 numpy.int_ 数据类型大小的整数(或布尔)数据类型,它将在内部向上转换为 numpy.int_ (或 numpy.uint ) 数据类型.

  • doc – 允许传入文档字符串以与 ufunc 一起存储.文档字符串不应包含函数名称或调用签名,因为这将从对象动态确定,并且在访问 ufunc 的 __doc__* 属性时可用.

  • unused – 未使用,为了 C-API 的向后兼容性而存在.

PyObject *PyUFunc_FromFuncAndDataAndSignature(PyUFuncGenericFunction *func, void *const *data, const char *types, int ntypes, int nin, int nout, int identity, const char *name, const char *doc, int unused, const char *signature)#

此函数与上面的 PyUFunc_FromFuncAndData 非常相似,但具有额外的 signature 参数,以定义 generalized universal functions .与 ufunc 围绕逐元素操作构建类似,gufunc 围绕子数组间的操作构建, signature 定义了要操作的子数组.

参数:
  • signature – 新gufunc的签名.设置为NULL等同于调用 PyUFunc_FromFuncAndData.将会复制字符串,因此可以释放传入的缓冲区.

PyObject *PyUFunc_FromFuncAndDataAndSignatureAndIdentity(PyUFuncGenericFunction *func, void **data, char *types, int ntypes, int nin, int nout, int identity, char *name, char *doc, int unused, char *signature, PyObject *identity_value)#

此函数与上面的 PyUFunc_FromFuncAndDataAndSignature 非常相似,但有一个额外的 identity_value 参数,用于为ufunc定义一个任意的identity,当 identity 作为 PyUFunc_IdentityValue 传递时.

参数:
  • identity_value – 新gufunc的identity.必须作为 NULL 传递,除非 identity 参数是 PyUFunc_IdentityValue .将其设置为NULL等同于调用 PyUFunc_FromFuncAndDataAndSignature.

int PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc, int usertype, PyUFuncGenericFunction function, int *arg_types, void *data)#

此函数允许用户将 1-d 循环注册到已创建的ufunc,以便在以用户定义的数据类型调用ufunc的任何输入参数时使用.为了使ufunc与内置数据类型一起工作, 这是必须的.该数据类型必须事先在numpy系统中注册.循环作为函数传入.该循环可以接受任意数据,这些数据应作为data传入.循环所需的数据类型作为arg_types传入,它必须是指向至少与 ufunc->nargs 一样大的内存的指针.

int PyUFunc_RegisterLoopForDescr(PyUFuncObject *ufunc, PyArray_Descr *userdtype, PyUFuncGenericFunction function, PyArray_Descr **arg_dtypes, void *data)#

此函数的行为类似于上面的 PyUFunc_RegisterLoopForType,不同之处在于它允许用户使用 PyArray_Descr 对象而不是 dtype 类型数值来注册 1-d 循环.这允许为结构化数组数据-dtypes 和自定义数据类型注册 1-d 循环,而不是标量数据类型.

int PyUFunc_ReplaceLoopBySignature(PyUFuncObject *ufunc, PyUFuncGenericFunction newfunc, int *signature, PyUFuncGenericFunction *oldfunc)#

用新的 1-d 循环 newfunc 替换已创建的ufunc中与给定签名匹配的 1-d 循环.在 oldfunc 中返回旧的 1-d 循环.成功时返回 0,失败时返回 -1.此函数仅适用于内置类型(对于用户定义的类型,使用 PyUFunc_RegisterLoopForType ).签名是一个数据类型编号数组,指示 1-d 循环假定的输入,然后是输出.

void PyUFunc_clearfperr()#

清除IEEE错误标志.

泛型函数#

每个ufunc的核心都是类型特定的函数集合,它定义了每种支持类型的基本功能.这些函数必须评估底层函数 \(N\geq1\) 次.可以传入额外的参数,这些参数可以在计算期间使用.这个特性允许一些通用函数被用作这些基本的循环函数.通用函数具有将变量指向正确位置并设置函数调用的所有代码.通用函数假定要调用的实际函数作为额外数据传入,并使用正确的值调用它.所有这些函数都适合直接放置在PyUFuncObject结构的函数的成员中存储的函数数组中.

void PyUFunc_f_f_As_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_f_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_g_g(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_F_F_As_D_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_F_F(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_D_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_G_G(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_e_e(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_e_e_As_f_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_e_e_As_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

类型特定的核心1-d函数,用于ufunc,其中每个计算通过调用一个接受一个输入参数并返回一个输出的函数来获得. 此函数在 func 中传入.字母对应于支持的数据类型的dtypechar( e - half, f - float, d - double, g - long double, F - cfloat, D - cdouble, G - clongdouble).参数func 必须支持相同的签名. _As_X_X 变体假定一个数据类型的ndarrays,但转换这些值以使用一个接受不同数据类型的底层函数.因此, PyUFunc_f_f_As_d_d 使用 NPY_FLOAT 数据类型的ndarray,但会调用一个接受double并返回double的C函数.

void PyUFunc_ff_f_As_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ff_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_gg_g(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_FF_F_As_DD_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_DD_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_FF_F(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_GG_G(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ee_e(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ee_e_As_ff_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ee_e_As_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

类型特定的核心1-d函数,用于ufunc,其中每个计算通过调用一个接受两个输入参数并返回一个输出的函数来获得. 要调用的底层函数作为 func 传入.这些字母对应于通用函数支持的特定数据类型的dtypechar.参数 func 必须支持相应的签名. _As_XX_X 变体假定一个数据类型的ndarray,但在循环的每次迭代中转换这些值,以使用接受不同数据类型的底层函数.

void PyUFunc_O_O(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_OO_O(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

NPY_OBJECT 数据类型使用的单输入单输出和双输入单输出核心 1-d 函数.这些函数处理引用计数问题,并在出错时提前返回.要调用的实际函数是 func ,它必须接受签名为 (PyObject) (PyObject) (对于 PyUFunc_O_O )或 (PyObject)(PyObject , PyObject ) (对于 PyUFunc_OO_O )的调用.

void PyUFunc_O_O_method(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

这个通用 1-d 核心函数假定 func 是一个字符串,表示输入对象的方法.对于循环的每次迭代,都从数组中提取 Python 对象,并调用其 func 方法,然后将结果返回到输出数组.

void PyUFunc_OO_O_method(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

这个通用 1-d 核心函数假定 func 是一个字符串,表示输入对象的一个方法,该方法接受一个参数. args 中的第一个参数是要调用其函数的 方法, args 中的第二个参数是传递给函数的参数. 该函数的输出存储在 args 的第三个条目中.

void PyUFunc_On_Om(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

这是由 umath.frompyfunc(function, nin, nout) 创建的动态 ufunc 使用的 1-d 核心函数. 在这种情况下, func 是指向 PyUFunc_PyFuncData 结构的指针,其定义为:

type PyUFunc_PyFuncData#
typedef struct {
    int nin;
    int nout;
    PyObject *callable;
} PyUFunc_PyFuncData;

在循环的每次迭代中,从其对象数组中提取 nin 个输入对象,并将它们放入一个参数元组中,使用输入参数调用 Python 可调用对象,然后将 nout 个输出放入其对象数组中.

导入 API#

PY_UFUNC_UNIQUE_SYMBOL#
NO_IMPORT_UFUNC#
int PyUFunc_ImportUFuncAPI(void)#

确保 UFunc C-API 已导入且可用.成功时返回 0 ,如果无法导入 NumPy 则返回 -1 并设置错误.虽然最好在模块初始化时调用一次,但多次调用此函数非常轻量.

在 2.0 版本加入: 此函数主要检查 PyUFunc_API == NULL ,因此如果需要可以手动向后移植.

import_ufunc(void)#

这些是用于从扩展模块访问 ufunc C-API 的常量和函数,其方式与访问数组 C-API 的方式完全相同.必须始终调用 import_ufunc () 函数(在扩展模块的初始化子例程中).如果您的扩展模块位于一个文件中,那么这就是所需的全部内容.如果您的扩展模块使用多个文件,则其他两个常量很有用.在这种情况下,将 PY_UFUNC_UNIQUE_SYMBOL 定义为代码所独有的内容,然后在不包含模块初始化函数但仍需要访问 UFUNC API 的源文件中,将 PY_UFUNC_UNIQUE_SYMBOL 定义为先前使用的相同名称,并定义 NO_IMPORT_UFUNC .

C-API 实际上是一个函数指针数组.这个数组由 import_ufunc 创建(并由一个全局变量指向).全局变量是静态定义的,还是允许被其他文件看到,取决于 PY_UFUNC_UNIQUE_SYMBOLNO_IMPORT_UFUNC 的状态.