文档章节

python拷贝

acutesun
 acutesun
发布于 2017/07/23 10:36
字数 1373
阅读 3
收藏 0
点赞 0
评论 0

先决条件

对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有拷贝这一说, 这种不可变对象存放在内存中的常量区. 该对象在常量区是唯一的
如果要使用该常量只有将内存地址赋值给对象的引用.

必要代码

import copy
listA = ['hello', 28, ['python', 'c#', 'javascript']]

打印列表A和B的id和打印A,B中元素的id

def print_id(listA, listB):
    print('listA:', id(listA))
    for ele in listA:
        print(str(ele) + ':', id(ele), end=' --> ')
    print()
    print('listB:', id(listB))
    for ele in listB:
        print(str(ele) + ':', id(ele), end=' --> ')
        

修改列表A的元素的值

def alter_A(listA): 
    listA[0] = 'hello222'
    listA[2].append('css')
    listA[1] = 55
    print(end='\n')
    print('分界线 对listA进行修改值操作:', end='\n \n')

将列表A赋值给列表B之后打印, 并将列表A元素的值修改后再次打印输出结果

def assignment():
    listB = listA
    print_id(listA, listB)
    alter_A(listA)
    print_id(listA, listB)

打印结果:

listA: 139643175769480
hello: 139643200213432 --> 28: 10915232 --> ['python', 'c#', 'javascript']: 139643175768968 --> 
listB: 139643175769480
hello: 139643200213432 --> 28: 10915232 --> ['python', 'c#', 'javascript']: 139643175768968 --> 
分界线 对listA进行修改值操作:
 
listA: 139643175769480
hello222: 139643175768368 --> 55: 10916096 --> ['python', 'c#', 'javascript', 'css']: 139643175768968 --> 
listB: 139643175769480
hello222: 139643175768368 --> 55: 10916096 --> ['python', 'c#', 'javascript', 'css']: 139643175768968 --> 

从打印结果可以看出所有的id都是相同的,对列表A进行修改就是对B修改

  • 结论: Python中,对象的赋值都是进行对象引用(内存地址)传递, listA is listB

将列表A浅拷贝给列表B之后打印, 并将列表A元素的值修改后再次打印输出结果

def light_copy():
    listB = copy.copy(listA)
    print_id(listA, listB)
    alter_A(listA)
    print_id(listA, listB)
    

打印结果:


listA: 140716204897416
hello: 140716229341624 --> 28: 10915232 --> ['python', 'c#', 'javascript']: 140716204897160 --> 
listB: 140716204908872
hello: 140716229341624 --> 28: 10915232 --> ['python', 'c#', 'javascript']: 140716204897160 --> 
分界线 对listA进行修改值操作:
 
listA: 140716204897416
hello222: 140716204896560 --> 55: 10916096 --> ['python', 'c#', 'javascript', 'css']: 140716204897160 --> 
listB: 140716204908872
hello: 140716229341624 --> 28: 10915232 --> ['python', 'c#', 'javascript', 'css']: 140716204897160 --> 

1.从输出可以看出浅拷贝创建了一个新的对象, 所以listA is not listB

2.但是对象中的元素, 浅拷贝会使用原来元素的引用(内存地址), 也就是说listA[n] is listB[n]

3.在对listA中的元素修改后, listA[0],listA[1]是不可变对象,所以指向了新的地址空间. listB[1],listB[0]仍然指向原来的地址空间.而listA[2]是一个可变对象列表.对其进行修改并不会指向一个新的地址空间. listB[2]也是指向相同的地址空间,所以listB[2]的值也被改变

  • 结论: Python中,浅拷贝会创建新对象, 但是仍然会使用原来对象指向的地址空间 浅拷贝之所以称为浅拷贝,是它仅仅只拷贝了一层,如果里面有嵌套对象,则不会创建新的对象,仍然使用原来的引用

  • 补充: 以下操作会产生浅拷贝

    使用切片[:]操作
    使用工厂函数(如list/dir/set)
    使用copy模块中的copy()函数

将列表A深拷贝给列表B之后打印, 并将列表A元素的值修改后再次打印输出结果

def deep_copy():
    listB = copy.deepcopy(listA)
    print_id(listA, listB)
    alter_A(listA)
    print_id(listA, listB)

打印结果:

listA: 140461809181960
hello: 140461833626040 --> 28: 10915232 --> ['python', 'c#', 'javascript']: 140461809182216 --> 
listB: 140461809181896
hello: 140461833626040 --> 28: 10915232 --> ['python', 'c#', 'javascript']: 140461809181768 --> 
分界线 对listA进行修改值操作:
 
listA: 140461809181960
hello222: 140461809180976 --> 55: 10916096 --> ['python', 'c#', 'javascript', 'css']: 140461809182216 --> 
listB: 140461809181896
hello: 140461833626040 --> 28: 10915232 --> ['python', 'c#', 'javascript']: 140461809181768 --> 

  1. 深拷贝同样会创建一个全新的对象 listA: 140461809181960 listB: 140461809181896 . 所以 listA is not listB

  2. 对象中的元素,深拷贝都会重新生成一份(有特殊情况, 比如listA中的字符串, 整数等, 开头已经介绍过), 而不是向浅拷贝那样使用原始元素的引用(内存地址)

  3. 深拷贝后 listA[2]的内存地址是140461809182216, listB[2]140461809181768
    所以 listA[2] is not listB[2].

  4. listA和listB中的字符串和整数对象都是指向的同一个内存地址, 对listA进行修改实质是指向了 新的内存地址. 而listB不变. 所以当对listA元素修改完全不影响listB, 两者是完全不同的对象

    注意: 每次打印结果可能不同

  • 结论:深拷贝会生成完全不同的对象

不可变对象不能进行深拷贝

def deep_copy2():
    a = ('abc', 12, (1, ))
    b = copy.deepcopy(a)
    print(a is b)

True


参考: link

总结

  • Python中对象的赋值都是进行对象引用(内存地址)传递

  • 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.

  • 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝

  • 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有被拷贝一说

  • 如果元祖变量只包含原子类型(不可变)对象,则不能深拷贝


完整代码:

import copy
listA = ['hello', 28, ['python', 'c#', 'javascript']]
def print_id(listA, listB):
    print('listA:', id(listA))
    for ele in listA:
        print(str(ele) + ':', id(ele), end=' --> ')
    print()
    print('listB:', id(listB))
    for ele in listB:
        print(str(ele) + ':', id(ele), end=' --> ')
def alter_A(listA):
    listA[0] = 'hello222'
    listA[2].append('css')
    listA[1] = 55
    print(end='\n')
    print('分界线 对listA进行修改值操作:', end='\n \n')
def assignment():
    listB = listA
    print_id(listA, listB)
    alter_A(listA)
    print_id(listA, listB)
def light_copy():
    listB = copy.copy(listA)
    print_id(listA, listB)
    alter_A(listA)
    print_id(listA, listB)
def deep_copy():
    listB = copy.deepcopy(listA)
    print_id(listA, listB)
    alter_A(listA)
    print_id(listA, listB)
def deep_copy2():
    a = ('abc', 12, (1, ))
    b = copy.deepcopy(a)
    print(a is b)
if __name__ == '__main__':
    # assignment()
    # light_copy()
    deep_copy2()

© 著作权归作者所有

共有 人打赏支持
acutesun
粉丝 0
博文 71
码字总数 83152
作品 0
程序员
【转载】如何制作python安装模块(setup.py)

Python 模块的安装方法: 单文件模块:直接把文件拷贝到 $PYTHON_DIR/lib 多文件模块,且带有 setup.py :只需执行 python setup.py install egg 文件:1) 下载 ezsetup.py ,运行 python e...

摩云飞
2013/01/04
0
0
Python动态类型的学习---引用的理解

一,Python浅拷贝和深拷贝 浅拷贝是指拷贝的只是原对象元素的引用,换句话说,浅拷贝产生的对象本身是新的,但是它的内容不是新的,只是对原对象的一个引用。这里有个例子 >>> aList=[[1, 2...

herlang
2013/04/10
0
0
python 的venv使用注意事项

在windows平台下的情况: 1、python的venv环境不能完全脱离python环境运行,就是你把整个项目拷贝到一台没有装python的电脑上,能运行venvScriptactivate进入虚拟环境,但运行scripts下的pyt...

良言
07/08
0
0
走进Python世界(二)搭建Python环境

Python 的环境配置 windows: windows 上搭建环境比较简单,直接下载安装包,直接安装即可, 安装完毕之后 E:PythonPython35Scripts;E:PythonPython35; 会被加入到 环境变量PATH 中。 Linux:...

Garrry
2015/07/16
0
0
最新阿里巴巴面试题(附带面试标准答案)

在上一节中,我们已经介绍了关于阿里巴巴的任职要求,这节我就详细的介绍一下关于阿里巴巴的面试题(涉及到标准代码部分不予以出现,如果想要可以加群:725479218,里面可以进行技术分享、技术...

柯西带你学编程
06/02
0
0
轻松使用OpenCV Python控制Webcam,读取Barcode

虽然手机上Barcode应用已经非常流行,但是工作的时候还是用Webcam比较方便。比如需要检测Barcode,我只需要拿Webcam对着电脑屏幕或者纸张扫一下就可以了。今天分享下如何轻松使用OpenCV控制W...

yushulx
2015/08/11
0
0
python pyrex windows 编译C可执行文件

python写成py文件经过处理转化成pyx文件,以及函数说明文件pyi使用pyrexc.py编译成对应模块的c和h文件 然后写一个main的cpp文件,使用cmake产生vs工程,使用incredBuild编译工程。 以下是一个...

悠米海
2012/09/25
0
0
Python常见经典 python中if __name__ == '__main__': 的解析

http://www.cnblogs.com/zhouxiansheng/p/3929247.html python中if name == 'main': 的解析 当你打开一个.py文件时,经常会在代码的最下面看到if name == 'main':,现在就来介 绍一下它的作用....

搬砖小哥
2017/11/02
0
0
使用Visual Studio,几步实现Python C++扩展,以及DLL调用

decodeFile(PyObject self, PyObject args){ } static PyMethodDef methods[] = { }; import DynamsoftBarcodeReader formats = { } def initLicense(license): def decodeFile(fileName): i......

yushulx
2015/05/26
0
0
关于center os yum卸载和python卸载后的解决办法

昨天配置代码审核工具reviewboard,这个是基于Python的框架Djanjo构建的,需要升级yum源,结果捣鼓来捣鼓去,系统一下子多了3 ,4个python,把Yum也搞坏了。后来不知道看了哪个损比写的帖子,把...

范思哲思考者
2014/07/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

对基于深度神经网络的Auto Encoder用于异常检测的一些思考

一、前言 现实中,大部分数据都是无标签的,人和动物多数情况下都是通过无监督学习获取概念,故而无监督学习拥有广阔的业务场景。举几个场景:网络流量是正常流量还是攻击流量、视频中的人的...

冷血狂魔
17分钟前
0
0
并发设计之A系统调用B系统

A-->B A在发送请求之前,用乐观锁,减少对B的重复调用,这样一定程度上是幂等性。 比如A系统支付功能,要调用B系统进行支付操作,但是前端对"支付"按钮不进行控制,即用户会不断多次点击支付...

汉斯-冯-拉特
37分钟前
0
0
HTTP协议通信原理

了解HTTP HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则。计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求信息和服务。 HTTP使用...

寰宇01
今天
0
0
【Java动态性】之反射机制

一、Java反射机制简介

谢余峰
今天
1
0
Centos 6.X 部署环境搭建

1.Linux学习笔记CentOS 6.5(一)--CentOS 6.5安装过程

IT追寻者
今天
0
0
博客即同步至腾讯云+社区声明

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=8vy9bsmadbko...

xiaoge2016
今天
1
0
大数据教程(3.1):Linux系统搭建网络YUM源服务器

博主在前面的2.5章节讲述了linux系统本地YUM服务器的搭建和httpd轻量级静态网站服务器的安装,本节博主将为大家分享内网环境中搭建自己的网络YUM服务器的全过程。如果大家对本地YUM服务器还不...

em_aaron
今天
1
0
蚂蚁技术专家:一篇文章带你学习分布式事务

小蚂蚁说: 分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在这几年越来越火的微服务架构中,几乎可以说是无法避免,本文就围绕分布式事务...

Java大蜗牛
今天
1
0
新的Steam应用将拓展服务项目

导读 未来几周,Steam将推出两个免费的应用程序Steam Link和Steam Video。这两个应用程序都旨在拓展Steam平台的业务和便利性。 即将开放的Steam Link应用程序最先提供了Android测试版,它将允...

问题终结者
今天
0
0
golang 第三方包的使用总结

golang 第三方包的安装的方法: 1. go get 安装 $ go get github.com/gin-gonic/gin 注意:执行go get 命令需要先安装git命令,并配置git全局变量。 2. 源码包安装 由于国内网络问题,很多时...

科陆李明
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部