设为首页 收藏本站
查看: 1422|回复: 0

[经验分享] [Python] 正确复制列表的方法

[复制链接]

尚未签到

发表于 2015-4-21 12:34:33 | 显示全部楼层 |阅读模式
new = old[:]
  
  Python老鸟都知道以上代码是什么意思。它复制列表old到new。它对于新手来说是种困惑而且应该避免使用这种方法。不幸的是[:]标记法被广泛使用,可能是Python程序员不知道更好的列表复制法吧。
  
  首先我们需要了解Python是如何管理对象和变量。Python没有C语言中的变量。在C语言中,变量不止是个名字,它是字节集合并真实存在于内存某个位置上。而在Python中,变量仅仅是指向对象的标签。
  
  看看以下语句:



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



b = a
  
  我们并没有复制a所指引的列表。我们只是创建了一个新的标签b,然后将其指向a所指向的列表。
DSC0000.png
  
  如果你修改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指引它。
DSC0001.png
  
  这其实就是 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才是包括子列表在内的完全复制。
  
  查看原文

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-59240-1-1.html 上篇帖子: Python快速学习02:基本数据类型 & 序列 下篇帖子: 黄聪:解决python中文处理乱码,先要弄懂“字符”和“字节”的差别
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表