直接用cythonize失败因它只生成.c文件,不编译链接为.so/.pyd;必须用setuptools驱动构建链,通过setup.py调用extension和cythonize,并设置compiler_directives。

为什么直接用 cythonize 会失败?
很多人跑完 cythonize 就以为生成了可加载的模块,结果 import 报错:ModuleNotFoundError 或 undefined symbol。根本原因:Cython 只把 .py 编译成 .c,不负责编译链接成 .so/.pyd。你得用 setuptools 驱动整个构建链。
正确做法是写一个 setup.py,调用 Extension 和 build_ext:
from setuptools import setup, Extension
from Cython.Build import cythonize
<p>ext_modules = [
Extension("my_module", ["my_module.pyx"]),
]
setup(
ext_modules = cythonize(ext_modules, compiler_directives={'language_level': 3})
)</p>
-
Extension的第一个参数是导入名(不是文件名),必须和.pyx文件 basename 一致 -
cythonize必须接收Extension列表,不能传字符串或路径列表 - 没加
compiler_directives时,默认按 Python 2 解析,print()会报错
如何让 def 函数真正变快?
只把 .py 改后缀成 .pyx 几乎没加速——Cython 默认仍走 Python 解释器路径。关键在声明类型和使用 cdef。
比如这个函数:
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
# my_module.pyx
def sum_range(int n):
cdef int i, total = 0
for i in range(n):
total += i
return total
-
cdef int i, total = 0告诉 Cython 这俩是 C int,循环变量不再走 Pythonint对象创建/销毁 -
def函数仍可被 Python 调用,但内部已去动态性;换成cdef就只能被同文件其他 Cython 函数调用 - 如果函数参数含
list、str等,别急着加cdef类型——Python 对象访问仍慢,优先考虑用memoryview或array.array
pyximport 适合调试,但别在线上用
pyximport.install() 确实能让你像导入普通模块一样 import mymod,但它会在运行时悄悄调用系统 gcc 编译,依赖本地编译环境,且每次 import 都检查时间戳重编译。
- 开发迭代快,但首次 import 可能卡住几秒——尤其模块大或机器慢时
- 线上环境通常没装
gcc、python-dev,pyximport直接崩溃 - 它绕过
setup.py,没法控制compiler_directives或链接额外库(如 OpenMP) - 真要热重载,建议用
cython -X手动生成.c,再用gcc手动编译测试
NumPy 数组怎么避免拷贝和类型检查开销?
直接对 numpy.ndarray 索引循环,性能往往比纯 Python 还差——因为每次 a[i] 都触发完整 Python 属性查找和 dtype 检查。
正确姿势是用 typed memoryview:
# my_module.pyx import numpy as np cimport numpy as cnp cimport cython <p>def process_array(double[:] arr): # memoryview,不复制 cdef Py_ssize_t i cdef double s = 0.0 for i in range(arr.shape[0]): s += arr[i] return s</p>
-
double[:]是 C 连续内存的只读 view,传入前需确保np.array(..., dtype=np.float64, order='C') - 如果需要修改数组,用
double[:]也可,但调用方传入必须是writeable=True - 别用
np.ndarray做参数类型注解——它仍是 Python 对象,Cython 不会优化访问 - 多维数组用
double[:, :],注意维度顺序和内存 layout 匹配
最易被忽略的是:即使写了 memoryview,如果传入的 NumPy 数组是非连续(arr.T)或 dtype 不匹配(int32 传给 double[:]),Cython 会静默复制一份新数组——性能反降。务必在调用前用 np.ascontiguousarray() 和 .astype() 显式转换。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










