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

[经验分享] 拷贝Python 对象

[复制链接]

尚未签到

发表于 2017-4-24 12:21:45 | 显示全部楼层 |阅读模式
  说当你创建一个
对象,然后把它赋给另一个变量的时候,Python 并没有拷贝这个对象,而是拷贝了这个对象的
引用。
比如,假设你想创建一对小夫妻的通用档案,名为person.然后你分别为他俩拷贝一份。
在下面的例子中,我们展示了两种拷贝对象的方式,一种使用了切片操作,另一种用了工厂方
法,为了区分出三个不同的对象,我们使用id()内建函数来显示每个对象的标识符。(我们还
可以用is 操作符来做相同的事情)
  >>> person = ['name', ['savings', 100.00]]
>>> hubby = person[:] # slice copy
>>> wifey = list(person) # fac func copy
>>> [id(x) for x in person, hubby, wifey]
[11826320, 12223552, 11850936]
  为他们创建了初始有$100 的个人存款帐户。用户名改为定制的名字。但是,当丈夫取走$50
后,他的行为影响到了他妻子的账户,虽然我们进行了分开的拷贝作(当然,前提是我们希望他
们每个人都拥有自己单独的帐号,而不是一个单一的联合帐号。)为什么会这样呢?
>>> hubby[0] = 'joe'
>>> wifey[0] = 'jane'
>>> hubby, wifey
(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
>>> hubby[1][1] = 50.00
>>> hubby, wifey
(['joe', ['savings', 50.0]], ['jane', ['savings', 50.0]])
原因是我们仅仅做了一个浅拷贝。对一个对象进行浅拷贝其实是新创建了一个类型跟原对
象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不
是.序列类型对象的浅拷贝是默认类型拷贝,并可以以下几种方式实施:(1)完全切片操作[:],(2)
利用工厂函数,比如list(),dict()等,(3)使用copy 模块的copy 函数.
你的下一个问题可能是:当妻子的名字被赋值,为什么丈夫的名字没有受到影响?难道它们
的名字现在不应该都是'jane'了吗?为什么名字没有变成一样的呢?怎么会是这样呢?这是因为
在这两个列表的两个对象中,第一个对象是不可变的(是个字符串类型),而第二个是可变的(一
个列表).正因为如此,当进行浅拷贝时,字符串被显式的拷贝,并新创建了一个字符串对象,而列
表元素只是把它的引用复制了一下,并不是它的成员.所以改变名字没有任何问题,但是更改他
们银行账号的任何信息都会引发问题.现在,让我们分别看一下每个列表的元素的对象ID 值,注
意,银行账号对象是同一个对象,这也是为什么对一个对象进行修改会影响到另一个的原因.注
意在我们改变他们的名字后,新的名字字符串是如何替换原有'名字'字符串的.
  BEFORE:
>>> [id(x) for x in hubby]
[9919616, 11826320]
>>> [id(x) for x in wifey]
[9919616, 11826320]
AFTER:
>>> [id(x) for x in hubby]
[12092832, 11826320]
>>> [id(x) for x in wifey]
[12191712, 11826320]
假设我们要给这对夫妻创建一个联合账户,那这是一个非常棒的方案,但是,如果需要的是
两个分离账户,就需要作些改动了.要得到一个完全拷贝或者说深拷贝--创建一个新的容器对象,
包含原有对象元素(引用)全新拷贝的引用--需要copy.deepcopy()函数.我们使用深拷贝来重
写整个例子.
>>> person = ['name', ['savings', 100.00]]
>>> hubby = person
>>> import copy
>>> wifey = copy.deepcopy(person)
>>> [id(x) for x in person, hubby, wifey]
[12242056, 12242056, 12224232]
>>> hubby[0] = 'joe'
>>> wifey[0] = 'jane'
>>> hubby, wifey
(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
>>> hubby[1][1] = 50.00
>>> hubby, wifey
(['joe', ['savings', 50.0]], ['jane', ['savings', 100.0]])
这就是我们想要的方式,作为验证,让我们确认一下所有四个对象都是不同的.
>>> [id(x) for x in hubby]
[12191712, 11826280]
  >>> [id(x) for x in wifey]
[12114080, 12224792]
以下有几点关于拷贝操作的警告。第一,非容器类型(比如数字,字符串和其他"原子"类型的
对象,像代码,类型和xrange 对象等)没有被拷贝一说,浅拷贝是用完全切片操作来完成的.第二,
如果元组变量只包含原子类型对象,对它的深拷贝将不会进行.如果我们把账户信息改成元组类
型,那么即便按我们的要求使用深拷贝操作也只能得到一个浅拷贝:
>>> person = ['name', ('savings', 100.00)]
>>> newPerson = copy.deepcopy(person)
>>> [id(x) for x in person, newPerson]
[12225352, 12226112]
>>> [id(x) for x in person]
[9919616, 11800088]
>>> [id(x) for x in newPerson]
[9919616, 11800088]
核心模块: copy
我们刚才描述的浅拷贝和深拷贝操作都可以在copy 模块中找到.其实copy 模块中只有两
个函数可用:copy()进行浅拷贝操作,而deepcopy()进行深拷贝操作.

运维网声明 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-368658-1-1.html 上篇帖子: GAE-oAuth-python 下篇帖子: python set使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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