当我将单个值分配给多维内存视图的切片时,Cython似乎使用了错误的步幅,除非切片沿着第一维。以下是一个完整的示例:
# bug.py
import numpy as np
def bug():
#cdef int[:, ::1] a
a = 2*np.ones((2, 2), dtype=np.intc)
a[:, :1] = 1
print(np.asarray(a))
如果我们在Python中运行这个代码(例如
python3 -c 'import bug; bug.bug()'
),我们会得到以下结果:[[1 2]
[1 2]]
按预期打印出来了。我现在将其重命名为bug.pyx
,使用Cython编译它,然后在同一目录下的Makefile
中保存以下内容:
# Makefile
python = python3
python_config = $(python)-config
CC = gcc
CFLAGS = $(shell $(python_config) --cflags) -fPIC
CFLAGS += $(shell $(python_config) --includes)
python_libdir = $(shell $(python) -c "import sysconfig; \
print(sysconfig.get_config_var('LIBDIR'));")
LDLIBS = -L$(python_libdir) -Wl,-rpath=$(python_libdir)
LDLIBS += $(shell $(python_config) --libs)
LDFLAGS = $(shell $(python_config) --ldflags) -shared
bug.so: bug.c; $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o bug.so bug.c
bug.c: bug.pyx; $(python) -m cython -3 $<
运行 make
命令。再次运行 python3 -c 'import bug; bug.bug()'
,它现在会加载已编译的 bug.so
文件,并输出结果。
[[1 2]
[1 2]]
如果现在我们取消注释
cdef
声明,然后运行 make
和 python3 -c 'import bug; bug.bug()'
,那么我们将会得到:[[1 1]
[2 2]]
这是错误的。我不认为 int[:, ::1]
声明是错误的,否则 Cython 会发出警告。如果我只用 int[:, :]
替换它,它就能工作。同时,如果我给 a
的第一维度赋值,a[:1, :] = 1
,它也能工作。
这是已知问题吗?或者我对 Cython 内存视图的这种看似基本的使用方式有误解吗?
print(a.flags)
,我们会看到a
确实是C连续的,因此int[:, ::1] a
是正确的。然而,print(a[:, :1].flags)
不是!我猜这就是问题的根源。 - jmd_dk