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才是包括子列表在内的完全复制。

查看原文

[Python] 正确复制列表的方法的更多相关文章

  1. python各种操作列表的方法及案例

    一.循环的使用方法 names = ["张真","刘德华","哈林","谢霆锋","张柏芝"] fo ...

  2. python笔记-list列表的方法

    #!usr/bin/python # -*- coding: utf-8 -*- # 存储5个人的年龄,求他们的平均年龄 age1 = 18 age2 = 15 age3 = 38 age4 = 20 ...

  3. python 正确复制list,克隆list 的各种方案

    推荐4种方法 --------------------------------------------------------------- 方法一:extend L = [1, 2, 3] List ...

  4. Python之复制列表

    将一个列表的数据复制到另外一个列表中. 1 a = [1,2,3] #定义列表a 2 3 b = a[:] #将列表a的切片赋值给b,也可以理解为将b的值设置为a[:] 4 5 print(a) #打 ...

  5. python中list列表的方法len()

    作用:返回列表中元素的个数. 用法: len(list)

  6. Python练习题——用列表的方法输出杨辉三角

    def main(): num = int(input('请输入行数: ')) yh = [[]] * num #创建num行空列表 for row in range(len(yh)): #遍历每一行 ...

  7. python遍历删除列表的方法

    for item in list(somelist): somelist.remove(item)

  8. python list删除数据 和复制 列表

    复制列表的方法: lst = [1,2,3] lst1 = lst[:] # one way lst2 = list(lst) # another 删除数据的正确方法: num_list = [1, ...

  9. python循环删除列表元素常见错误与正确方法

    python循环删除列表元素 觉得有用的话,欢迎一起讨论相互学习~Follow Me 常见错误 常见错误一:使用固定长度循环删除列表元素 # 使用固定长度循环pop方法删除列表元素 num_list_ ...

随机推荐

  1. Qt QTcpSocket 对连接服务器中断的不同情况进行判定

    简述 对于一个C/S结构的程序,客户端有些时候需要实时得知与服务器的连接状态.而对于客户端与服务器断开连接的因素很多,现在就目前遇到的情况进行一下总结. 分为下面六种不同情况 客户端网线断开 客户端网 ...

  2. 《FPGA全程进阶---实战演练》第八章之程序架构格式说明

    首先在书写程序时必须有的部分,就是模块module部分,整体的架构如图8.1所示. 图8.1 程序整体架构 首先要声明模块名,在module后面加上模块名,这里最好以所建立模块要实现的功能去命名此模块 ...

  3. 【转】【Android】Android Studio打包全攻略

    项目写完了,现在需要把应用上传到市场,问题出现—怎么把代码变成.apk(Android的可安装文件).1. 创建签名文件2. 填写好签名参数3. 生成APK注意:签名的密码和密匙的密码注意保管,不要忘 ...

  4. 认真研究下HTML之id、name、form、submit

    #起因 同事希望在提交之后关闭父窗口,但是,始终没有提交请求发出.他的代码大概如下: // <form id='f' action=... // <button onclick='fun( ...

  5. CSS之float vs position:absolute

    补充:ul 应该设置下 list-style: none; 题外话:看了张鑫旭的视频,这家伙把简单的css玩出了新花样,绝对大神级的存在.膜拜下先~ float的作用前面一章已经说过了,但没考虑过的是 ...

  6. Spring JDBC SimpleJdbcCall类示例

    org.springframework.jdbc.core.SimpleJdbcCall类是表示对存储过程或存储函数的调用的多线程,可重用的对象. 它提供元数据处理以简化访问基本存储过程/函数所需的代 ...

  7. 混合线路接入时,360、QQ管家等测速显示电信IP或任意线路的IP

    最近很多人QQ上问我,我有电信.联通接入,用户测速的时候有的时候显示联通的IP,可是我想让他显示为电信的IP,怎么办? 3年前开始使用联通的线路时,就这样设置了,有些人还拿这个设置当宝贝了???? 其 ...

  8. iOS7以上: 实现如“日历”的 NavigationBar

    第一步,隐藏导航栏底部的分割线 如何隐藏导航栏底部的分割线(shadow image/ hairline)? navigationBar.clipsToBounds = YES; //隐藏 navig ...

  9. 'AndroidManifest.xml' must have a minimum of 2 segments.

    Manifest下必须有二级域名 <manifest xmlns:android="http://schemas.android.com/apk/res/android" p ...

  10. fedora26 编译内核出现Can't use 'defined(@array)' 错误

    cd /kernel/ vim timeconst.pl 把373行中的if (!defined(@val)) { 改为if (!@val) {