使用 Cython 时缺少 numpy 属性

Gin*_*ger 3 python numpy cython

我有一个非常简单的 cython 模块,名为empty_test.pyx

cimport numpy as cnp


cpdef return_empty():
    return cnp.empty(0, dtype=np.int32)
Run Code Online (Sandbox Code Playgroud)

当我尝试运行时,出现return_empty此错误:

empty_test.pyx:5:14: cimported module has no attribute 'empty'
Run Code Online (Sandbox Code Playgroud)

这是我的setup.py文件:

from distutils.core import setup
from Cython.Build import cythonize

import numpy as np
setup(
    ext_modules=cythonize(['empty_test.pyx'],
    ),
    include_dirs = [np.get_include()],
)
Run Code Online (Sandbox Code Playgroud)

我知道我可以尝试import numpy as np代替cimport numpy as np,但我正在尝试使用 numpy 代码的 C 版本。

ead*_*ead 5

为了实现这一点,您必须直接访问 numpy 的 C-API,它至少部分由 Cython 包装。在您的情况下,您需要numpyPyArray_SimpleNew已经cimported

因此,您的功能变为:

%%cython
cimport numpy as cnp

cnp.import_array()  # needed to initialize numpy-API

cpdef return_empty():
    cdef cnp.npy_intp dim = 0
    return cnp.PyArray_SimpleNew(1, &dim, cnp.NPY_INT32)
Run Code Online (Sandbox Code Playgroud)

现在:

>>> return_empty()
array([], dtype=int32)
Run Code Online (Sandbox Code Playgroud)

显然,由于引用计数,仍然有一些 Python 开销,但它要少得多,就像使用时一样np.empty()

>>> %timeit return_empty()   
159 ns ± 2.81 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit return_empty_py
751 ns ± 8.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Run Code Online (Sandbox Code Playgroud)

使用PyArray_SimpleNew也比使用 Cython 更快(大约 3 倍)array(正如您在另一个问题中所考虑的那样):

%%cython
from cython.view cimport array as cvarray

# shape=(0,) doesn't work
cpdef create_almost_empty_carray():
    return cvarray(shape=(1,), itemsize=sizeof(int), format="i")
Run Code Online (Sandbox Code Playgroud)

因此:

>>> %timeit create_almost_empty_carray()
435 ns ± 5.85 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Run Code Online (Sandbox Code Playgroud)

使用的功能列表return_empty_py

%%cython
cimport numpy as cnp
import numpy as np

cpdef return_empty_py():
    return np.empty(0, np.int32)
Run Code Online (Sandbox Code Playgroud)