创建 Numpy ufuncs

注意

此页面使用两种不同的语法变体

  • Cython 特定的 cdef 语法,旨在使类型声明简洁明了,并易于从 C/C++ 的角度阅读。

  • 纯 Python 语法,允许在 纯 Python 代码 中进行静态 Cython 类型声明,遵循 PEP-484 类型提示和 PEP 526 变量注释。

    要在 Python 语法中使用 C 数据类型,您需要在要编译的 Python 模块中导入特殊的 cython 模块,例如

    import cython
    

    如果您使用纯 Python 语法,我们强烈建议您使用最新的 Cython 3 版本,因为与 0.29.x 版本相比,这里已经进行了重大改进。

Numpy 支持一种 称为 ufunc 的特殊函数类型。这些支持数组广播(即处理具有任意数量维度的参数的能力),以及其他有用功能。

Cython 可以通过使用 @cython.ufunc 装饰器标记 Cython C 函数来生成 ufunc。输入和输出参数类型应该是标量变量(“通用 ufuncs”尚未支持),并且应该是 Python 对象或简单的数字类型。此类函数的主体被插入到一个高效的编译循环中。

import cython

@cython.ufunc
@cython.cfunc
def add_one(x: cython.double) -> cython.double:
    # of course, this simple operation can already by done efficiently in Numpy!
    return x+1

您的函数可以有任意数量的参数。如果您想拥有多个输出参数,则可以使用 ctuple 语法

import cython

@cython.ufunc
@cython.cfunc
def add_one_add_two(x: cython.int) -> tuple[cython.int, cython.int]:
    return x+1, x+2

如果您想接受多个不同的参数类型,则可以使用 融合类型(模板)

import cython

@cython.ufunc
@cython.cfunc
def generic_add_one(x: cython.numeric) -> cython.numeric:
    return x+1

最后,如果您将 cdef/@cfunc 函数声明为 nogil,那么 Cython 将在生成的 ufunc 中释放 GIL。这与 nogil 函数的一般行为略有不同(它们通常不会自动释放 GIL,而是可以在没有 GIL 的情况下运行)。

此功能依赖于 Numpy。因此,如果您在 Cython 中创建 ufunc,则在构建生成的 C 代码时必须提供 Numpy 头文件,并且用户在运行模块时必须安装 Numpy。