集合减法运算符与.difference()方法速度差异及实现区别解析
集合差集操作:
-运算符与.difference()的实现差异及CPython/PyPy区别 测试背景
求两个集合的差集可通过-运算符或.difference()方法实现,以下是对比两者性能的测试代码:
import timeit print(timeit.timeit(''' a.difference({b}) ''', setup=''' a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} b = 3 ''')) # => 0.2423834060318768 print(timeit.timeit(''' a - {b} ''', setup=''' a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} b = 3 ''')) # => 0.2027170000365004
不同解释器下的测试结果
- CPython运行输出:
0.24530324200168252 0.205820870003663
可见-运算符的执行速度比.difference()更快。
- PyPy运行输出:
0.14613953093066812 0.23659668595064431
结果完全反转,.difference()的性能反超-运算符。
核心差异解析
-运算符与.difference()的实现区别
参数要求与处理
-运算符:要求右侧必须是集合类型,底层直接调用集合的__sub__特殊方法,跳过了类型检查和可迭代对象适配的步骤,仅针对集合执行差集计算。.difference()方法:支持接收任意可迭代对象(如列表、元组),底层会先将传入的可迭代对象转换为临时集合,再执行差集逻辑。即便传入的是集合,方法本身仍会执行参数类型检查的流程,带来微小的额外开销。
调用路径开销
.difference()是普通方法调用,需要经过属性查找(定位a的difference属性)、方法绑定等步骤,这一系列操作会产生额外的执行成本。-运算符是语言层面的语法糖,直接映射到__sub__方法,调用路径更短,在无JIT优化的解释器中优势明显。
CPython与PyPy的实现区别
JIT编译优化差异
- PyPy自带JIT即时编译,会对高频执行的代码路径进行深度优化。在本次测试场景中,PyPy能识别到
.difference()的参数始终是集合,提前消除了不必要的类型转换与检查逻辑,甚至直接内联方法核心代码,使得方法调用的额外开销被完全抹平,最终性能反超运算符。 - CPython是纯字节码解释执行,无JIT优化,运算符更短的调用路径(跳过属性查找与方法绑定)带来的性能优势更突出。
- PyPy自带JIT即时编译,会对高频执行的代码路径进行深度优化。在本次测试场景中,PyPy能识别到
底层实现逻辑不同
- CPython的集合基于C语言实现,
__sub__与difference最终调用同一个底层C函数,但difference多了一层参数处理逻辑(检查可迭代对象、转换为集合),即使传入集合也无法完全跳过这层检查,产生微小开销。 - PyPy的集合用RPython实现,其方法调用优化机制对
.difference()更友好,结合JIT的动态优化,最终实现了比运算符更高效的执行效果。
- CPython的集合基于C语言实现,
内容的提问来源于stack exchange,提问作者Michael M.
相关产品推荐
相关产品推荐

