博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 深浅拷贝 (Shallow copy and Deep copy in Python)
阅读量:7223 次
发布时间:2019-06-29

本文共 1905 字,大约阅读时间需要 6 分钟。

前言

昨天刷公众号看到一篇描述,心痒之下到家就开始尝试,学习了for else statement,yield和py版三目写法。在列表切片这部分中,对作者的列表拷贝写法,有些不太理解。

# 拷贝copy_items = items[::] 或者 items[:]

尝试

首先开一个python,随便建一个列表

l=[1,2,3]
将其进行两种方法的拷贝:

  1. 我的写法
    c=l
  2. 作者的写法
    d=l[:]

分别打印了cd,并没有什么差别,仔细斟酌了一下作者的用意,觉得应该有一些深层次的考虑。

于是使用id()分别查看两边的内存地址,这一打印出现了不同的结果。

>>> id(l)39179656L>>> id(c)39179656L>>> id(d)39179272L

使用直接赋值的c的内存地址和原列表l的内存地址是一样的,而用切片方法拷贝的d的内存地址不一样。

我尝试改动l的值看一下结果。

>>> l.append('z')>>> l[1, 2, 3, 'z']>>> c[1, 2, 3, 'z']>>> d[1, 2, 3]

此时区别就显示出来了,使用直接赋值的c因为和原列表l指向同一个内存地址,所以当修改l的值的时候,打印c也发现同样的改变。

探索

稍微搜一下,发现这个是有专有名词的,叫做 “深浅拷贝” (copy,deepcopy)。我原来直接赋值的写法只是将内存地址的引用传递到一个新的对象里,连浅拷贝都算不上。

Python的拷贝有一个专门的模块,叫做copy

浅拷贝

import copy;>>> l=[1,2,3,[4,5],6]>>> c=copy.copy(l)>>> id(l)39195912L>>> id(c)39238600L

从内存引用里清晰的显示,至少内存地址不一样了,对l进行内容变更应该不会影响到c

>>> l.append('z')>>> l[1, 2, 3, [4, 5], 6, 'z']>>> c[1, 2, 3, [4, 5], 6]

但是毕竟是浅拷贝,只是拷贝了最外层对象,没有拷贝子对象。

>>> id(l[3])39195784L>>> id(c[3])39195784L>>> l[3].append('az')>>> l[1, 2, 3, [4, 5, 'az'], 6, 'z']>>> c[1, 2, 3, [4, 5, 'az'], 6]

果然原列表l的子对象的内存地址和浅拷贝c的对应子对象的内存地址一样,所以当原列表的子对象内容发生改变时,也会影响到c

深拷贝

有了浅拷贝的经验,直接造一个深拷贝对象d,先查看一下外层对象和子对象的内存地址。

>>> l=[1,2,3,[4,5],6]>>> d=copy.deepcopy(l)>>> id(l)39236296L>>> id(d)39195912L>>> id(l[3])39179656L>>> id(d[3])39236040L

结果清晰的显示,原列表l和深拷贝对象d对应外层对象和子对象的内存地址均不同。

>>> l.append('z')>>> l[1, 2, 3, [4, 5], 6, 'z']>>> d[1, 2, 3, [4, 5], 6]>>> l[3].append('az')>>> l[1, 2, 3, [4, 5, 'az'], 6, 'z']>>> d[1, 2, 3, [4, 5], 6]

再查看一下结果,验证了我的猜想。

总结

Python是一门脚本语言,声明一个对象实际在内存中创建了一个地址存放对象,将对象名指向那个内存地址。用PHP的赋值方法进行赋值时,只是创建了一个新的对象名同时指向同一个内存地址。

的作者所用的列表拷贝方法c=l[:]用的就是浅拷贝,只是写法相对于copy.copy()更简洁。
通过Copy模块的代码可以发现deepcopy是在copy的基础上执行了递归。

# C:\Python27\Lib\copy.pydef deepcopy(x, memo=None, _nil=[]):...y = _reconstruct(x, rv, 1, memo);...def _reconstruct(x, info, deep, memo=None):...if deep:args = deepcopy(args, memo);...

备注:本文发布于2017-08-03,我github page的。

转载于:https://www.cnblogs.com/waltersgarden/p/7991733.html

你可能感兴趣的文章
jquery插件开发样例-jquery插件开发(1)
查看>>
Android 基本UI控件
查看>>
数据库内核月报 - 2015 / 10-MySQL · 特性分析 · 跟踪Metadata lock
查看>>
fedora 中设置mysql编码
查看>>
jquery选择器案例
查看>>
【存储】megacli 常用参数介绍
查看>>
基于CoreText的基础排版引擎之不带图片的排版引擎
查看>>
椒盐噪声
查看>>
可动态扩展的数据库模型设计
查看>>
Spring MVC视图解析器:配置多个视图解析器的优先级
查看>>
J.U.C并发框架
查看>>
纸上谈兵: 伸展树 (splay tree)[转]
查看>>
Hibernate_学习之问题集
查看>>
退出、测试、判断及操作符
查看>>
ClassNotFoundException和NoClassDefFoundError的区别
查看>>
查看perl模块和cpan模块介绍
查看>>
使用微信登录
查看>>
有关在hyper-V上安装红帽redhat 6.1网卡相关问题
查看>>
解决ssh连接一段时间后光标无响应问题
查看>>
2012-3-16 - 一周心情
查看>>