【发布时间】:2018-08-08 12:31:40
【问题描述】:
我在Pandas source看到过几次这样的事情:
def nancorr(ndarray[float64_t, ndim=2] mat, bint cov=0, minp=None):
# ...
N, K = (<object> mat).shape
这意味着一个名为 mat 的 NumPy ndarray 是 Python 对象的 type-casted。*
经过进一步检查,似乎使用了这个,因为如果不是,则会出现编译错误。我的问题是:为什么首先需要这种类型转换?
这里有几个例子。 This 答案只是表明元组打包在 Cython 中不像在 Python 中那样工作——但这似乎不是元组解包问题。 (无论如何,这是一个很好的答案,我不想挑剔它。)
采用以下脚本,shape.pyx。它会在编译时失败,并显示“无法将 'npy_intp *' 转换为 Python 对象。”
from cython cimport Py_ssize_t
import numpy as np
from numpy cimport ndarray, float64_t
cimport numpy as cnp
cnp.import_array()
def test_castobj(ndarray[float64_t, ndim=2] arr):
cdef:
Py_ssize_t b1, b2
# Tuple unpacking - this will fail at compile
b1, b2 = arr.shape
return b1, b2
但同样,问题本身似乎并不是元组解包。这将失败并出现相同的错误。
def test_castobj(ndarray[float64_t, ndim=2] arr):
cdef:
# Py_ssize_t b1, b2
ndarray[float64_t, ndim=2] zeros
zeros = np.zeros(arr.shape, dtype=np.float64)
return zeros
看起来,这里没有进行元组拆包。元组是np.zeros 的第一个参数。
def test_castobj(ndarray[float64_t, ndim=2] arr):
"""This works"""
cdef:
Py_ssize_t b1, b2
ndarray[float64_t, ndim=2] zeros
b1, b2 = (<object> arr).shape
zeros = np.zeros((<object> arr).shape, dtype=np.float64)
return b1, b2, zeros
这也有效(也许是最令人困惑的):
def test_castobj(object[float64_t, ndim=2] arr):
cdef:
tuple shape = arr.shape
ndarray[float64_t, ndim=2] zeros
zeros = np.zeros(shape, dtype=np.float64)
return zeros
例子:
>>> from shape import test_castobj
>>> arr = np.arange(6, dtype=np.float64).reshape(2, 3)
>>> test_castobj(arr)
(2, 3, array([[0., 0., 0.],
[0., 0., 0.]]))
*也许它与arr 是一个内存视图有关?但这是在黑暗中的一枪。
另一个例子是 Cython docs:
cpdef int sum3d(int[:, :, :] arr) nogil:
cdef size_t i, j, k
cdef int total = 0
I = arr.shape[0]
J = arr.shape[1]
K = arr.shape[2]
在这种情况下,简单地索引arr.shape[i] 可以防止错误,我觉得这很奇怪。
这也有效:
def test_castobj(object[float64_t, ndim=2] arr):
cdef ndarray[float64_t, ndim=2] zeros
zeros = np.zeros(arr.shape, dtype=np.float64)
return zeros
【问题讨论】:
-
我不知道 Cpython,但至少在
c中,如果arr.shape返回一个指针(似乎),你(和 numpy)没有办法知道它的维度。