如何实现无复用的生成器笛卡尔积且避免使用deepcopy
高效获取笛卡尔积中全新的生成器对象
问题背景
我有两个生成器用于生成数据:
def xs(): yield [1, 2] yield [3, 4] def ys(): yield [5, 6] yield [7, 8]
需要处理所有(x,y)笛卡尔积对:
process([1, 2], [5, 6]) process([1, 2], [7, 8]) process([3, 4], [5, 6]) process([3, 4], [7, 8])
现有方案存在的问题:
itertools.product:生成器产出的对象会被复用,若process修改数据,后续处理会出现错误。- 嵌套循环:仅能避免
y的复用,x仍会被多次传递同一对象,修改后会影响后续迭代。 deepcopy:能解决对象复用问题,但性能极差,无法满足效率要求。
基准测试结果(生成100个含100个整数的列表,process为空操作):
0.6 ± 0.0 ms using_product 3.1 ± 0.0 ms nested_loops 404.7 ± 25.9 ms with_deepcopy
需求:不使用deepcopy,始终获取全新的x和y对象,执行效率约为nested_loops的两倍。
解决方案:按需浅拷贝生成器对象
核心思路是对生成器产出的列表做浅拷贝(针对仅含不可变元素的列表,浅拷贝足够生成独立新对象,且开销远低于deepcopy),确保每次传递给process的都是全新对象。
实现代码
方案1:基于itertools.product的拷贝版本
def product_with_copy(xs, ys, process): for x, y in product(xs(), ys()): process(x.copy(), y.copy())
方案2:优化嵌套循环(减少重复拷贝)
def nested_loops_with_copy(xs, ys, process): for x in xs(): base_x = x.copy() for y in ys(): process(base_x.copy(), y.copy())
先对每个x做一次初始拷贝,内层循环再拷贝该副本,避免重复生成x的初始拷贝,进一步优化效率。
测试结果
将两个新方案加入基准测试后,结果如下(同测试环境):
0.6 ± 0.0 ms using_product 3.1 ± 0.0 ms nested_loops 6.2 ± 0.1 ms nested_loops_with_copy 6.3 ± 0.1 ms product_with_copy 404.7 ± 25.9 ms with_deepcopy
可以看到,两个新方案的耗时约为nested_loops的两倍,完全符合效率要求,且性能远优于deepcopy版本。
原理说明
- 列表的
copy()方法是浅拷贝,对于包含不可变元素(如整数)的列表,能生成完全独立的新对象,避免原对象被修改后影响后续迭代。 - 浅拷贝仅复制列表的引用结构,无需递归复制内部元素,因此性能开销极小。
- 方案2的优化点在于减少了
x的重复拷贝次数,进一步降低了整体耗时。
内容的提问来源于stack exchange,提问作者no comment
相关产品推荐
相关产品推荐

