深度列表列表(速度问题)

时间:2014-05-19 06:18:16

标签: python

由于配方不清楚,我决定重写我的问题: 我的代码看起来像这样(org应该是列表和两个整数的列表):

def my_copy(org):
    temp = (tuple(org[0]), org[1], org[2])
    temp2 = []
    temp2.append(list(temp[0]))
    temp2.append(temp[1])
    temp2.append(temp[2])
    return temp2
a = [[1,2,3], 4, 5]
b = []
for i in range(5):
    b.append(my_copy(a))

现在我可以在不影响其他副本的情况下更改b的元素。不像我使用

b.append(copy.copy(a)) 在循环中

我这样做是为了避免使用看起来很慢的copy.deepcopy()。现在有三个问题:此代码是否生成了我的列表的深度复制?如果没有,为什么它仍然创建副本而不仅仅是b.append(a)的新引用?另外:我怎么能以更优雅,快速和pythonic的方式做到这一点?

1 个答案:

答案 0 :(得分:3)

这里似乎存在一些误解,即浅拷贝和深拷贝之间的区别。您在问题中说明您要附加列表列表。我们假设以下是这样的列表:

In [32]: x = [[1,2,3],[4,5,6]]

在浅拷贝中,我们只复制第一层。来自文档:

  

浅复制构造一个新的复合对象,然后(尽可能)将对它的引用插入到原始对象中找到的对象。

In [33]: z = []

# using the method you describe
In [35]: z.append(list(tuple(list(x))))

In [36]: z
Out[36]: [[[1, 2, 3], [4, 5, 6]]]

如果我们现在修改z的内容,我们会更改x,因为我们使用了浅层副本。

In [38]: z[0][0][0]=7

In [39]: x
Out[39]: [[7, 2, 3], [4, 5, 6]]

在深层复制中,我们在所有级别制作对象的副本,实质上是创建原始对象的克隆。来自文档:

  

深层复制构造一个新的复合对象,然后以递归方式将副本插入到原始对象中找到的对象。

In [40]: import copy 

In [41]: z = []

In [42]: x = [[1,2,3],[4,5,6]]

In [43]: z.append(copy.deepcopy(x))

In [44]: z
Out[44]: [[[1, 2, 3], [4, 5, 6]]]

In [45]: z[0][0][0] = 7

In [46]: x
Out[46]: [[1, 2, 3], [4, 5, 6]]

Numpy可能是解决此问题的最快解决方案,但您必须重构代码才能获得收益。如果您在循环的基本级别中的列表和数组之间进行转换,Numpy将不会使您受益。相反,你应该尽早尝试解决问题,并尽量减少类型转换的次数。

修改

查看更新问题,似乎有一个非常简单的解决方案。如果列表中的列表只包含不可变类型,则可以使用以下任一项:

def my_copy_1(org):
    return (copy.copy(org[0]),org[1],org[2])

def my_copy_2(org):
    return (org[0][:],org[1],org[2])

根据原始实现测试速度,我得到:

In [2]: a = [[1,2,3],1,2]

In [3]: %timeit tmp.my_copy_orig(a)
100000 loops, best of 3: 2.05 µs per loop

In [4]: %timeit tmp.my_copy_1(a)
100000 loops, best of 3: 2.06 µs per loop

In [5]: %timeit tmp.my_copy_2(a)
1000000 loops, best of 3: 784 ns per loop

在速度方面,my_copy_2似乎是明显的赢家。您可以使用以下命令测试它是否产生了正确的行为:

In [6]: a = [[1,2,3],1,2]

In [7]: z = tmp.my_copy_2(a)

In [8]: z[2] = 999

In [9]: z[0][0] = 999

In [10]: a
Out[10]: [[1, 2, 3], 1, 2]

In [11]: z
Out[11]: [[999, 2, 3], 1, 999]