reversed()函数与切片反转的性能对比及差异原因探究
字符串反转迭代器 vs 切片的性能差异
以下是两个功能完全相同的函数,分别通过reversed()迭代器和字符串切片[::-1]实现:
def count1(text): c = 0 for i, j in zip(text, reversed(text)): if i == j: c += 1 return c def count2(text): c = 0 for i, j in zip(text, text[::-1]): if i == j: c += 1 return c
原本认为count2()性能会不如count1()——因为count1()仅使用迭代器,不会创建新的字符串对象。但实际测试发现:短字符串场景下确实是count1()更快,但随着字符串长度增加,count2()的运行速度会反超count1(),两者差异虽小但值得探究。
测试脚本
from timeit import timeit from random import choices from string import ascii_lowercase for k in range(2, 21, 2): print(f'{k=}') text = ''.join(choices(ascii_lowercase, k=k)) for func in count1, count2: print(func.__name__, f'{timeit(lambda: func(text)):.4f}')
测试结果
字符串长度小于12时,count1()更快;长度超过12后,count2()运行速度反超。
测试环境
- macOS 13.3
- Python 3.11.2
- CPU:3GHz 10-Core Intel Xeon W
- RAM:32GB
性能反转的原因
- 迭代器的解释层开销:
reversed()返回的是迭代器对象,每次迭代都需要调用其__next__()方法,这个过程存在Python解释器层面的额外开销。短字符串迭代次数少,这种开销占比高,盖过了切片创建新字符串的成本。 - 切片的底层高效实现:字符串切片
[::-1]是在C层面完成的内存复制,效率极高。当字符串变长时,创建反转字符串的一次性成本会被后续迭代的低开销摊薄——切片生成的反转字符串是连续内存块,迭代时能更好利用CPU缓存,访问速度更快。 - Python 3.11的针对性优化:Python 3.11对字符串操作做了多项性能提升,包括切片的内存操作优化和字符串迭代的缓存友好性,进一步放大了长字符串场景下切片的优势。
- zip的迭代效率差异:当
zip迭代两个原生字符串(原字符串和切片生成的反转字符串)时,整个迭代过程是纯C层面操作;而迭代reversed()对象时,每次取元素都要经过迭代器的Python层逻辑,随着迭代次数增加(字符串变长),累计开销会越来越大。
内容的提问来源于stack exchange,提问作者jackal
相关产品推荐
相关产品推荐

