python正确复制列表

[Python] 正确复制列表的方法

new = old[:]

 

Python老鸟都知道以上代码是什么意思。它复制列表old到new。它对于新手来说是种困惑而且应该避免使用这种方法。不幸的是[:]标记法被广泛使用,可能是Python程序员不知道更好的列表复制法吧。

 

首先我们需要了解Python是如何管理对象和变量。Python没有C语言中的变量。在C语言中,变量不止是个名字,它是字节集合并真实存在于内存某个位置上。而在Python中,变量仅仅是指向对象的标签。

 

看看以下语句:

a = [1, 2, 3]

 

它表示我们创建了一个指引指向列表[1, 2, 3],但是a不是列表。如果:

b = a

 

我们并没有复制a所指引的列表。我们只是创建了一个新的标签b,然后将其指向a所指向的列表。

 

如果你修改a,那你就同时修改了b,因为它们指向同一个列表:

复制代码
>>> a = [1, 2, 3]
>>> b = a
>>> a.append(4)
>>> print a
[1, 2, 3, 4]
>>> print b
[1, 2, 3, 4]
复制代码

 

内建函数id()可以返回对象的唯一id。该id是对象的内存地址。

复制代码
>>> id(a)
3086056
>>> id(b)
3086056
>>> c = [] # Create a new list
>>> id(c)
2946712
复制代码

 

可以看出a和b都指向同一个内存地址。c指向一个新建的空列表,因此指向了不同的地址。

 

现在我们要复制a指引的列表。我们必须创建新的列表,然后使用b指引它。

 

这其实就是 new = old[:]。切片运算符[:]返回一个序列的切片。切片过程是切下列表的一部分,创建新的列表,将切下的部分复制到新列表。

复制代码
>>> a[1:3]
[2, 3]
>>> id(a)
3086056
>>> id(a[1:3])
3063400
复制代码

 

省略第一个索引值,切片从列表开始,省略第二个索引值,切片直到列表末端。

>>> a[:3]
[1, 2, 3]
>>> a[1:]
[2, 3, 4]

 

通过调用a[:],我们得到一个从列表首端开始到末端的切片,也就是a(指引的列表)的完整复制。但这不是复制列表的唯一方式。看看下面这个情况:

复制代码
>>> b = list(a)
>>> id(a)
3086056
>>> id(b)
3086256
复制代码

 

这个是不是看起来更好,少一些隐式,更加pythonic?a[:]看起来有点太像Perl。不同于切片标记法,不了解Python的人也会明白b是一个列表。

 

list()是列表构造函数。它会在传入的数列基础上新建一个列表。数列不一定是列表,它可以是任何类型的数列。

复制代码
>>> my_tuple = (1, 2, 3)
>>> my_list = list(my_tuple)
>>> print my_list
[1, 2, 3]
>>> id(my_tuple)
3084496
>>> id(my_list)
3086336
复制代码

 

而且它还接受生成器。切片笔记法不适用于生成器,因为生成器是不可更改。你不能generator[0],例如:

>>> generator = (x * 3 for x in range(4))
>>> list(generator)
[0, 3, 6, 9]

 

百分之九十的切片标记法都可以被list()代替。下次你看见[:]的时候试试使用list()替代,这样可以让你的代码更加可读。记住,魔鬼藏在细节里。

 

附:五种复制方法的比较

复制代码
>>> import copy
>>> a = [[10], 20]
>>> b = a[:]
>>> c = list(a)
>>> d = a * 1
>>> e = copy.copy(a)
>>> f = copy.deepcopy(a)
>>> a.append(21)
>>> a[0].append(11)
>>> print id(a), a
30553152 [[10, 11], 20, 21]
>>> print id(b), b
44969816 [[10, 11], 20]
>>> print id(c), c
44855664 [[10, 11], 20]
>>> print id(d), d
44971832 [[10, 11], 20]
>>> print id(e), e
44833088 [[10, 11], 20]
>>> print id(f), f
44834648 [[10], 20]
复制代码

从以上可以看出,使用 a[:], list(a), a*1, copy.copy(a)四种方式复制列表结果都可以得到一个新的列表,但是如果列表中含有列表,所有b, c, d, e四个新列表的子列表都是指引到同一个对象上。只有使用copy.deepcopy(a)方法得到的新列表f才是包括子列表在内的完全复制。

rel:http://www.cnblogs.com/ifantastic/p/3811145.html
### 如何在Python正确复制列表Python 中,可以通过多种方法来实现列表复制。具体来说,有浅拷贝(shallow copy)和深拷贝(deep copy),两者的区别在于是否递归地复制嵌套对象。 #### 浅拷贝 (Shallow Copy) 浅拷贝会创建一个新的容器,但是该容器中的元素仍然是原对象的引用。如果原列表中有嵌套的对象(如子列表或其他可变数据结构),修改这些嵌套对象会影响浅拷贝后的版本[^1]。 以下是使用 `copy` 模块进行浅拷贝的例子: ```python import copy original_list = [1, 2, [3, 4]] shallow_copy = copy.copy(original_list) original_list[2][0] = 5 print("Original List:", original_list) # 输出: Original List: [1, 2, [5, 4]] print("Shallow Copy:", shallow_copy) # 输出: Shallow Copy: [1, 2, [5, 4]] ``` 可以看到,在修改了 `original_list` 的嵌套列表 `[3, 4]` 后,`shallow_copy` 中对应的嵌套列表也被改变了[^3]。 另一种实现浅拷贝的方法是切片操作或者直接调用列表构造函数: ```python # 使用切片操作 slice_copy = original_list[:] # 或者使用 list 构造器 constructor_copy = list(original_list) ``` 以上两种方式均适用于仅含不可变对象的一维列表,但对于包含可变对象的复杂列表,则可能无法完全隔离两者之间的关联[^2]。 --- #### 深拷贝 (Deep Copy) 深拷贝不仅会创建新的外层容器,还会递归地复制所有内部对象。因此,即使原列表中含有嵌套的可变对象,也不会影响到深拷贝的结果[^1]。 下面是利用 `copy.deepcopy()` 实现深拷贝的示例代码: ```python import copy original_list = [1, 2, [3, 4]] deep_copy = copy.deepcopy(original_list) original_list[2][0] = 5 print("Original List:", original_list) # 输出: Original List: [1, 2, [5, 4]] print("Deep Copy:", deep_copy) # 输出: Deep Copy: [1, 2, [3, 4]] ``` 从上面可以看出,尽管更改了 `original_list` 嵌套列表的内容,但 `deep_copy` 并未受到影响[^3]。 --- ### 总结 - 如果只需要简单地复制一层列表而无需考虑其中的嵌套对象,可以选择 **浅拷贝**。 - 当面对复杂的、含有嵌套可变对象的数据结构时,应采用 **深拷贝** 来确保独立性。 选择合适的复制策略取决于实际需求以及目标数据的具体特性[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值