文档章节

python拷贝

acutesun
 acutesun
发布于 2017/07/23 10:36
字数 1373
阅读 3
收藏 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
程序员
jupyter、pyenv、virtualenv、virtualenvwrapper简要区别

一、区别 1.jupyter 对接ipython,作为一个web端的notebook,便于python工作。 2.pyenv 在创建一个新的python版本时,完全拷贝一个现成的python环境。新的python版本,可作为global 3.virtua...

xiaoge2016
08/10
0
0
最常见的 35 个 Python 面试题及答案(2018 版)

雷锋网按:本文为 AI 研习社编译的技术博客,原文 Top 35 Python Interview Questions and Answers in 2018 ,作者 DataFlair Team。 翻译 | 于志鹏 整理 | 凡江 1. Python 面试问题及答案 ...

雷锋字幕组
08/02
0
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编程之赋值和拷贝的区别概述及操作excel数据库(图)

python编程之赋值和拷贝的区别概述及操作excel数据库(图) 一、赋值 在Python中,对象的赋值就是简单的对象引用,这点和C++不同,如下所示: a = [1,2,”hello”,[‘python’, ‘C++’]] b ...

原创小博客
08/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSX | SafariBookmarksSyncAgent意外退出解决方法

1. 启动系统, 按住⌘-R不松手2. 在实用工具(Utilities)下打开终端,输入csrutil disable, 然后回车; 你就看到提示系统完整性保护(SIP: System Integrity Protection)已禁用3. 输入reboot回车...

云迹
今天
3
0
面向对象类之间的关系

面向对象类之间的关系:is-a、has-a、use-a is-a关系也叫继承或泛化,比如大雁和鸟类之间的关系就是继承。 has-a关系称为关联关系,例如企鹅在气候寒冷的地方生活,“企鹅”和“气候”就是关...

gackey
今天
4
0
读书(附电子书)|小狗钱钱之白色的拉布拉多

关注公众号,在公众号中回复“小狗钱钱”可免费获得电子书。 一、背景 之前写了一篇文章 《小狗钱钱》 理财小白应该读的一本书,那时候我才看那本书,现在看了一大半了,发现这本书确实不错,...

tiankonguse
今天
4
0
Permissions 0777 for ‘***’ are too open

异常显示: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ......

李玉长
今天
5
0
区块链10年了,还未落地,它失败了吗?

导读 几乎每个人,甚至是对通证持怀疑态度的人,都对区块链的技术有积极的看法,因为它有可能改变世界。然而,区块链技术问世已经10年了,我们仍然没有真正的用上区块链技术。 几乎每个人,甚...

问题终结者
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部