ufunc API#
常量#
UFUNC_{THING}_{ERR}
宏#
-
NPY_LOOP_BEGIN_THREADS#
在通用函数代码中使用,仅在 loop->obj 为 true 时释放 Python GIL(即这不是 OBJECT 数组循环)。要求在变量声明区域使用
NPY_BEGIN_THREADS_DEF。
-
NPY_LOOP_END_THREADS#
在通用函数代码中使用,用于重新获取 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。版本 1.23.0 中已更改: 除了
NULL值数组外,还接受NULLdata。
这是一个为 doubles 加法返回 doubles 的函数示例。
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; } }
-
void loopfunc(char **args, npy_intp const *dimensions, npy_intp const *steps, void *data)#
函数#
-
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 循环的指针。
注意
func、data、types、name 和 doc 参数不会被
PyUFunc_FromFuncAndData复制。调用者必须确保这些数组使用的内存不会被释放,只要 ufunc 对象仍然存在。- 参数:
func – 必须指向一个包含 ntypes 个
PyUFuncGenericFunction元素的数组。data – 应为
NULL或指向大小为 ntypes 的数组的指针。此数组可以包含传递给 func 数组中相应循环函数的任意额外数据,包括NULL。types –
长度为
(nin + nout) * ntypes的char数组,编码了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_MinusOne或PyUFunc_None。这指定了当空数组传递给 ufunc 的 reduce 方法时应返回什么。特殊值PyUFunc_IdentityValue只能与PyUFunc_FromFuncAndDataAndSignatureAndIdentity方法一起使用,以允许使用任意 python 对象作为标识符。name – ufunc 的名称,作为
NULL终止的字符串。指定名称“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 参数,用于定义一个 广义通用函数。 类似于 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 参数,用于定义当 identity 参数为
PyUFunc_IdentityValue时 ufunc 的任意标识符。- 参数:
identity_value – 新 gufunc 的标识符。除非 identity 参数是
PyUFunc_IdentityValue,否则必须将其设置为NULL。将其设置为 NULL 等同于调用 PyUFunc_FromFuncAndDataAndSignature。
-
int PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc, int usertype, PyUFuncGenericFunction function, int *arg_types, void *data)#
此函数允许用户为一个已创建的 ufunc 注册一个 1-d 循环,以便在 ufunc 被调用并使用任何输入参数作为用户定义数据类型时使用。这对于使 ufunc 与内置数据类型协同工作是必需的。数据类型必须已预先注册到 numpy 系统。循环作为 function 传入。此循环可以接受任意数据,应将其作为 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 循环。这使得 1-d 循环可以为结构化数组数据类型和自定义数据类型而不是标量数据类型注册。
-
int PyUFunc_ReplaceLoopBySignature(PyUFuncObject *ufunc, PyUFuncGenericFunction newfunc, int *signature, PyUFuncGenericFunction *oldfunc)#
用新的 1-d 循环 newfunc 替换已创建的 ufunc 中与给定 signature 匹配的 1-d 循环。将旧的 1-d 循环函数存储在 oldfunc 中。成功返回 0,失败返回 -1。此函数仅适用于内置类型(用户定义类型请使用
PyUFunc_RegisterLoopForType)。签名是一个数据类型编号数组,指示 1-d 循环接受的输入(后跟输出)。
-
void PyUFunc_clearfperr()#
清除 IEEE 错误标志。
通用函数#
每个 ufunc 的核心是一组特定于类型的函数,它们定义了每种支持类型的基本功能。这些函数必须评估底层函数 \(N\geq1\) 次。可以传入额外数据,这些数据可在计算过程中使用。此功能允许一些通用函数用作这些基本循环函数。通用函数包含将变量指向正确位置并设置函数调用的所有代码。通用函数假定要调用的实际函数作为额外数据传入,并使用正确的值调用它。所有这些函数都适合直接放置在 PyUFuncObject 结构体的 functions 成员的函数数组中。
-
void PyUFunc_f_f_As_d_d(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_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)#
用于ufunc的特定类型、核心1-d函数,其中每个计算都是通过调用一个接受一个输入参数并返回一个输出的函数来获得的。该函数通过
func传递。字母对应于支持的数据类型的dtypechar(e- half,f- float,d- double,g- long double,F- cfloat,D- cdouble,G- clongdouble)。参数 func 必须支持相同的签名。 _As_X_X 变体假定ndarray的类型为一种,但会将值转换为使用接受不同数据类型的底层函数。因此,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_As_DD_D(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)#
用于ufunc的特定类型、核心1-d函数,每个计算都是通过调用一个接受两个输入参数并返回一个输出的函数来获得的。要调用的底层函数作为 func 传递。字母对应于通用函数支持的特定数据类型的dtypechar。参数
func必须支持相应的签名。_As_XX_X变体假定ndarray为一种数据类型,但在循环的每次迭代时将值转换为使用接受不同数据类型的底层函数。
-
void PyUFunc_OO_O(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
NPY_OBJECT数据类型的单输入单输出和双输入单输出核心 1-d 函数。这些函数处理引用计数问题并在出错时提前返回。要调用的实际函数是 func,它必须接受以下签名的调用:对于PyUFunc_O_O,签名是(PyObject*) (PyObject*);对于PyUFunc_OO_O,签名是(PyObject*)(PyObject *, PyObject *)。
-
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 的 callable ,最后将 nout 个输出放入它们的对应对象数组中。
-
type PyUFunc_PyFuncData#
导入 API#
-
PY_UFUNC_UNIQUE_SYMBOL#
-
NO_IMPORT_UFUNC#
-
int PyUFunc_ImportUFuncAPI(void)#
确保 UFunc C-API 已导入并可用。如果 NumPy 导入成功,则返回 0;如果 NumPy 导入失败但设置了错误,则返回 -1。虽然最好在模块初始化时调用一次,但如果多次调用,此函数开销很小。
版本 2.0 中新增: 此函数主要检查
PyUFunc_API == NULL,因此如果需要,可以手动向后移植。
-
import_ufunc(void)#
这些是用于从扩展模块访问 ufunc C-API 的常量和函数,其方式与访问 array C-API 完全相同。必须始终调用
import_ufunc() 函数(在扩展模块的初始化子程序中)。如果您的扩展模块位于一个文件中,那么这就足够了。另外两个常量在您的扩展模块使用多个文件时非常有用。在这种情况下,将PY_UFUNC_UNIQUE_SYMBOL定义为您代码中的一个唯一名称,然后在不包含模块初始化函数但仍需要访问 UFUNC API 的源文件中,将PY_UFUNC_UNIQUE_SYMBOL定义为先前使用的相同名称,并同时定义NO_IMPORT_UFUNC。C-API 实际上是一个函数指针数组。这个数组由 import_ufunc 创建(并由一个全局变量指向)。全局变量要么是静态定义的,要么允许被其他文件看到,具体取决于
PY_UFUNC_UNIQUE_SYMBOL和NO_IMPORT_UFUNC的状态。