You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现无复用的生成器笛卡尔积且避免使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:03:21