公共Cython接口¶
自2020年4月起,本网站中的以下模块通过公共 cdef
Cython API声明:
scipy.linalg.cython_blas
scipy.linalg.cython_lapack
scipy.optimize.cython_optimize
scipy.special.cython_special
这是用来 Cython's declaration sharing features ,共享位置 cdef
项在中声明 *.pxd
与二进制SciPy安装中相应的DLL/SO文件一起分发的文件。
应用程序二进制接口¶
然而,在SciPy中使用这些功能需要SciPy贡献者在维护应用程序二进制接口(ABI)稳定性方面格外小心。这类似于用C语言开发库,而不同于纯Python中的向后兼容工作方式。
与Python的主要区别在于头文件中的声明 .pxd
当用户编写的代码是 已编译 ,但当用户代码为时,它们还必须与SciPy中的可用内容相匹配 已导入 。
用户代码可以使用一个版本的SciPy进行编译,编译后的二进制文件(使用中声明的二进制接口 .pxd
文件)可以与系统上安装的不同的SciPy版本一起使用。如果接口不兼容,要么会引发异常,要么会导致运行时内存损坏和崩溃。
导入时,Cython检查已安装的SciPy SO/DLL文件中函数的签名是否与 .pxd
用户在编译期间使用的文件,如果不匹配则引发Python异常。如果SciPy代码的结构正确(见下文),则仅对用户代码中实际导入的函数执行此检查。
我们依赖此功能来提供运行时安全检查,这使得用户可以更容易地通过Python异常检测不兼容的SciPy版本,而不是难以跟踪的运行时崩溃。
ABI稳定目标¶
SciPy旨在维护Cython代码中的ABI稳定性,具体体现在以下几个方面:
通过使用一个版本的SciPy编译用户源代码所产生的二进制文件与可以编译源代码的任何其他SciPy版本兼容。
尝试在运行时使用不兼容的SciPy版本将导致在用户模块导入时出现Python异常。
试图在编译时使用不兼容的SciPy版本将导致Cython错误。
这意味着用户可以使用任何兼容版本的SciPy来编译二进制文件,而不必关注ABI,即,
ABI兼容性=API兼容性
Cython API向后/向前兼容性将使用与Python API类似的弃用/删除策略进行处理,请参见 不推荐使用 。
在SciPy中实现ABI稳定性¶
为了维护上述ABI稳定性目标,在SciPy中开发Cython API时需要遵循以下规则:
添加新的
cdef
声明(函数、结构、类型等) 是允许的 。删除
cdef
声明 是允许的 ,但是 应该紧随其后 一般弃用/删除策略。cdef
函数的声明 可能会更改 。但是,更改会导致向后不兼容的API更改,该更改会破坏使用更改的签名的任何代码,并且 应该紧随其后 一般弃用/删除策略。
cdef
任何其他内容的声明(例如struct
,enum
和类型)是 最终版 。一旦在发布的SciPy版本的公共CythonAPI中暴露声明, 它不能更改 。如果需要更改,则需要通过添加具有不同名称的新声明并删除旧声明来执行更改。
cdef
类是 不允许 在公共API中(待定:cdef类的向后兼容性需要更多的研究,但当我们不确定时一定不能允许)对于每个公共API模块(如
scipy.linalg.cython_blas
),使用单一界面.pxd
声明文件。公共接口声明文件 不应该 包含
cimport
结算单。如果是这样的话,Cython的签名检查将检查所有cimport函数,而不仅仅是用户代码使用的函数,因此更改其中一个函数会破坏整个API。如果需要数据结构, 首选不透明结构 在公共API中。接口声明不应包含任何结构成员声明。数据结构的分配、释放和属性访问应该通过函数来完成。
不推荐使用公共Cython API¶
要弃用公共Cython API函数,例如:
# scipy/something/foo.pxd
cdef public int somefunc()
# scipy/something/foo.pyx
cdef public int somefunc():
return 42
您可以使用 scipy._lib.deprecation.deprecate_cython_api
函数在相应的 .pyx
文件::
# scipy/something/foo.pyx
cdef public int somefunc():
return 42
from scipy._lib.deprecation import deprecate_cython_api
import scipy.something.foo as mod
deprecate_cython_api(mod, "somefunc", new_name="scipy.something.newfunc",
message="Deprecated in Scipy 1.5.0")
del deprecate_cython_api, mod
在此之后,Cython模块 cimport somefunc
,将发出一个 DeprecationWarning 在导入时。
不推荐使用Cython数据结构和类型。但是,在API中使用它们的所有函数都已经过弃用循环后,可以将其删除。
整个Cython模块可以与Python模块类似地弃用,方法是发出 DeprecationWarning 在顶层。