
写Python的人经常盯着大O符号看。他们花时间选对数据结构,用上生成器,避开嵌套循环。这些做法没错。可代码跑起来还是慢,尤其当数据量上去以后。问题往往藏在更细的地方。下面说三个点,每个都能让执行时间掉一截。
细节一 · 局部变量比全局变量快
很多人知道这条规则,但没用到点子上。看一段代码。
import time SIZE = 10000000 def use_global(): total = 0 for i in range(SIZE): total += i return total def use_local(): total = 0 r = range s = SIZE for i in r(s): total += i return total start = time.perf_counter() use_global() print(time.perf_counter() - start) start = time.perf_counter() use_local() print(time.perf_counter() - start)
跑一下会发现第二个函数快15%左右。原因不复杂。Python在函数内部访问局部变量用的是数组下标,访问全局变量要查字典。range和SIZE在第二个函数里变成了局部名字,每次循环少一次字典查找。一千万次循环,省下的时间肉眼可见。
更隐蔽的地方在循环内部反复调用全局函数。比如你写math.sqrt(x),每次都要先找math这个全局名字,再找sqrt属性。改成from math import sqrt,然后在函数开头写sqrt_local = sqrt,循环里用sqrt_local。速度能再提一截。这个做法不改变逻辑,只换名字的查找路径。
细节二 · 字符串拼接用 join
但知道为什么的人不多。先看错误示范。
def bad_concat(n): s = '' for i in range(n): s += str(i) return s
字符串在Python里不可变。每次s += str(i)都创建一个新字符串,把旧内容复制过去。n等于十万时,内存分配和复制次数是平方级的。改成列表收集再join。
def good_concat(n): parts = [] for i in range(n): parts.append(str(i)) return ''.join(parts)
join只分配一次内存,把所有片段按顺序填进去。十万次拼接,bad_concat要几秒,good_concat几十毫秒。差别不在算法,在内存操作次数。
有人会说f-string不是更快吗?f-string适合格式化少量变量。循环里拼大量字符串,join还是首选。如果拼接的片段类型固定,可以预先算好每个片段长度,用bytearray或者直接写文件。但多数场景下join足够。
细节三 · 用 __slots__ 减少实例内存
这个对速度的影响是间接的,但效果明显。看一个普通类。
class Point: def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) print(p.__dict__)
每个实例有一个字典存属性。字典方便,能动态加属性。代价是内存占用大,属性访问要查字典。如果类里属性固定,加一行__slots__ = ('x', 'y')。
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) # p.__dict__ 会报错,没有字典了
实例不再有字典,属性存在固定偏移的位置。访问p.x变成直接取内存地址的值,比查字典快。创建一百万个Point实例,内存能省一半以上。内存省了,CPU缓存命中率上去,整体循环处理这些对象的速度跟着涨。实测在属性读写密集的循环里,用__slots__能快20%到30%。
注意__slots__不是万能。继承时要小心,子类如果没定义__slots__,还是会生成字典。另外不能动态加属性,代码里如果有p.z = 3会直接报错。适合数据类、几何点、配置项这种字段固定的场景。
这三个细节都不改代码逻辑。局部变量、join拼接、__slots__,每一个都能单独用。合在一起,一个处理百万级数据的脚本,运行时间可能从十秒掉到三秒。优化不是玄学,是搞清楚解释器在背后做了什么。你少让它干一次活,它就快一次。
以上就是“Python代码优化:3个被忽视的细节,让运行速度飞起来”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14537/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料