Cython 编译错误“常量表达式中不允许”

Posted

技术标签:

【中文标题】Cython 编译错误“常量表达式中不允许”【英文标题】:Cython compilation error "Not allowed in a constant expression" 【发布时间】:2018-02-28 14:39:27 【问题描述】:

以下

cimport cython

@cython.boundscheck(False)
def boundtest():
     cdef int r=4
     cdef double l[3]

工作正常。但是当我尝试这个时:

cimport cython

@cython.boundscheck(False)
def boundtest():
     cdef int r=4
     cdef double l[r]

我收到以下错误:

[1/1] Cythonizing test.pyx

Error compiling Cython file:
------------------------------------------------------------
...
cimport cython

@cython.boundscheck(False)
def boundtest():
     cdef int r=4
     cdef double l[r]
                   ^
------------------------------------------------------------

test.pyx:13:20: Not allowed in a constant expression
     

添加装饰器是因为找到了 this 相关的 stackexchange 帖子并阅读了 Kurt W. Smith 的 Cython 书。据我所知,这应该可以告诉 Cython 不要担心可能由动态索引变量导致的越界错误,但由于某种原因它没有。我也尝试在编译器选项和全局范围内更改边界检查无济于事。

如果不是 Cython 文档声称是最新的,我会认为 boundscheck 已经贬值了。

【问题讨论】:

【参考方案1】:

失败与cython.boundscheck无关。

Boundchecking 只是检查您是否尝试访问不存在的数组元素。例如,如果您有一个大小为 4 的数组并尝试访问元素 5 - 使用 boundscheck(True) 它将给您一个异常,使用 boundscheck(False) 它将导致未定义的行为(可能导致分段错误)。

编译失败的原因还有一个:不能创建动态长度的静态数组!在编译时需要知道元素的数量,这只是c 强制执行的(我猜)。

但是您可以将r 定义为compile time:

DEF r=4

cimport cython

@cython.boundscheck(False)
def boundtest():
    cdef double l[r]

但是,您可以简单地创建一个 NumPy 数组并将其存储在 memoryview 变量中:

cimport cython
import numpy as np

@cython.boundscheck(False)
def boundtest():
    cdef int r=4
    cdef double[:] l = np.empty(r, dtype=np.double)

【讨论】:

成功了,非常感谢!我希望链接帖子中的 OP 能够更明确地更改他的代码以使用 memoryview 变量。 @Takoda Cython 结合了 Python 和 C,因此需要对两者都有一些了解才能正确使用。可能只是“假设”您不使用 cdef double l[r] 创建动态长度数组,而仅使用 cdef double l[4] 等已知常量。 奇怪的是 Cython 不支持 C99 VLA,但对它们有好处。 VLA 很危险。

以上是关于Cython 编译错误“常量表达式中不允许”的主要内容,如果未能解决你的问题,请参考以下文章

在 Cython 中使用 move 方法时出现编译错误

python / cython编译pyx:致命错误:capsule.h:没有这样的文件或目录

尝试运行已编译的 Cython 代码时出现“python39.dll not found”错误 [重复]

OSX 的 Cython 链接错误

Cython 抛出语法错误

重载 operator() 在 Cython 中失败