Python函数调用开销主要来自栈帧创建,而非计算本身;规避方法是内联、向量化或Cython:删函数定义直接展开表达式,或用np.vectorize/Cython cdef inline避免Python层调度。
Python函数调用开销无法绕过,但能有效规避——关键不是“优化调用”,而是“不调用”。
为什么
会吃掉 62 秒?
你看到的不是算法慢,是 Python 解释器在反复创建栈帧:每次
被调用,都要分配帧对象、压栈、查局部变量、执行、弹栈。对 1200 万次调用来说,这比计算本身还重。
尤其当函数体只有
这种两行表达式时,栈帧开销远超计算开销。
它被嵌在
链中,三层调用 = 三倍帧开销
和
是
,但
是 C 实现,快;瓶颈纯在 Python 层调度
对这种参数几乎不重复的场景无效,反而增加哈希和字典查找
直接内联:把函数体写进调用点
最简单有效的办法,就是删掉函数定义,把逻辑粘贴到它被调用的地方。别担心“破坏封装”,高频小计算不值得抽象。
立即学习
“
Python免费学习笔记(深入)
”;
比如原来:
改成:
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
更进一步,直接展开:
去掉命名函数调用,避免全局名查找 + 栈帧创建
仍建函数对象,但比命名函数少一层作用域查找
如果
是 numpy 数组,考虑用向量化:
,一次性算完
用
写 Cython 内联函数
当内联后仍不够快(比如你后续要加更多距离逻辑),就该切到 Cython。注意:必须用
,不是
。
在
中写:
然后在 Python 中调用:
函数编译为纯 C 函数,调用不进 Python 栈,无帧开销
不能传
直接进去,需先解包为
或
;否则又触发 Python 对象转换
若需批量计算,改用
包裹或直接写 NumPy 向量化逻辑,别走 Python 循环
闭包里缓存局部引用能省一点,但别指望太多
如果你必须保留函数结构(比如多个距离函数共用一套签名),可以靠闭包减少运行时查找:
这能省掉两次全局变量查找(
),但栈帧照常创建,收益有限(约 5–10%)
只在函数体稍复杂、且无法内联时考虑;对单行表达式,不如直接展开
别用
替代,它只是包装器,额外多一层调用
真正卡性能的从来不是“怎么调得更快”,而是“能不能不调”。栈帧机制是 CPython 的硬约束,所有装饰器、缓存、优化技巧都绕不开这点——能提前展开就别封装,能向量化就别循环,能 C 层算就别留 Python 层。
taxicab_distancetaxicab_distance(u, v)np.abs(u[0] - v[0]) + np.abs(u[1] - v[1])agent.calc → squaregrid.distance → taxicab_distanceuvnumpy.ndarraynp.abslru_cachedef choose_max_distance_to(self, robot, target):
candidates = self.neighbours(robot) + [robot]
return max(candidates, key=lambda r: taxicab_distance(r, target))
def choose_max_distance_to(self, robot, target):
candidates = self.neighbours(robot) + [robot]
def _dist(u, v):
return np.abs(u[0] - v[0]) + np.abs(u[1] - v[1])
return max(candidates, key=lambda r: _dist(r, target))
def choose_max_distance_to(self, robot, target):
candidates = self.neighbours(robot) + [robot]
return max(candidates, key=lambda r: np.abs(r[0] - target[0]) + np.abs(r[1] - target[1]))
lambdacandidatesnp.abs(candidates[:, 0] - target[0]) + np.abs(candidates[:, 1] - target[1])cdefcdef inlinedefdistance.pyxcdef inline double taxicab_dist(double x1, double y1, double x2, double y2):
return abs(x1 - x2) + abs(y1 - y2)
from distance cimport taxicab_dist
注意:传标量,不是 array
score = taxicab_dist(robot[0], robot[1], target[0], target[1])
cdef inlinenumpy.ndarrayfloatdoublenp.vectorizeimport numpy as np
把 np.abs 提前绑定,避免每次进函数都查 global np
def make_taxicab():
_abs = np.abs
def dist(u, v):
return _abs(u[0] - v[0]) + _abs(u[1] - v[1])
return dist
taxicab_distance = make_taxicab()
np.absfunctools.partial