详解python浅拷贝与深拷贝

0. 介绍

浅拷贝:只拷贝父对象,不拷贝内部子对象

nums = [1, 2, 3, [4, 5]]
nums_copy = nums.copy()
nums[0], nums[3][0] = 8, 100
print(nums)
print(nums_copy)

# 输出
# nums: [8, 2, 3, [100, 5]]
# nums_copy: [1, 2, 3, [100, 5]]

深拷贝:完全拷贝了父对象及其子对象

import copy

nums = [1, 2, 3, [4, 5]]
nums_copy = copy.deepcopy(nums)
nums[0], nums[3][0] = 8, 100
print(nums)
print(nums_copy)

# 输出
# nums: [8, 2, 3, [100, 5]]
# nums_copy: [1, 2, 3, [4, 5]]

深拷贝与浅拷贝的使用大致如此,只是作为一个API记住没有任何的难度,如果你的目标仅仅在于了解如何使用,那么本文对你的帮助到此就为止了。如果你有足够的好奇心,想了解其中的原理,那么可以继续往下看,我会对它的原理进行详细分析。

1. 对象模型

为了让大家更好以及更透彻的理解python的浅拷贝与深拷贝,我们先来简单的说一下python的对象模型。如果你有研究过python的源码,那么对于对象模型就一定不会感到陌生。

首先这里要给出一个重要的结论:在python中,一切皆对象

和C++以及Java一样,python也是一个面向对象的程序语言,但不同的是,python是一个 完全面向对象 的语言,怎么去理解这句话呢?请看下面这个例子

以C语言为例,定义一个变量 a 并初始化为1,再定义一个变量 b,以 a 赋值:

int a = 1;
int b = a;

C语言中,这两个变量在内存的分配情况就如上图所示,二者位于不同的内存区域。这也是比较符合我们认知的,那么在python中也是如此吗?我们来看看下面一段代码:


惊奇地看到, ab 这两个变量的地址居然是相同的!这似乎不符合常理!但这也恰恰印证了我们前面提到了结论,在python中,一切皆对象, ab 仅仅只是两个名字,它们都指向了内存中同一个整数对象:

如果这还不能打动到你,我们再看一段代码:


这里只对变量 a 做了个自增运算,但同一个变量自增前与自增后的地址竟然发生了变化!这是怎么回事?

其实原因也很简单,整数对象在python中被称为 不可变对象,也就是说它们的值一旦确定就不可更改,我们这里对变量 a 做的自增运算,会让python在内存中重新创建一个整数对象,两个不同的对象在内存中的地址自然也是不同的:


既然有 不可变对象,那么对应的一定存在 可变对象,在python中典型的可变对象就是列表(List)


往列表里头追加数据,发现列表对象还是原来那个,只不过多了一个元素。实际上,列表对象内部维护了一个 动态数组 ,存储元素对象的指针。列表对象增减元素,需要修改该数组,例如,追加元素 3 :


2. 直接赋值

了解python对象模型的基本概念之后,从这个角度来理解浅拷贝与深拷贝就会轻松不少,在此之前,我们先来说一下直接赋值,以python基础数据结构列表(List)为例:


这里我们只改变了 nums 列表中的元素,但是却影响到了 nums_copy,通过前面学到的知识,很容易明白变量只是个名字,二者其实指向的是同一个对象,即同一个内存地址(不信的话可以亲自动手打印一下这两个列表的地址,会发现地址值是相同的),所以只要修改其中一个,另一个势必也会跟着改变:

3. 浅拷贝

同样对于列表 numsnums_copy,如果采用浅拷贝的方式(这里的nums[:]等同于nums.copy()),二者就不会指向同一个地址空间了,即它们是两个独立的列表对象,但是它们的子对象仍然是相同的,文字叙述起来可能还是比较晦涩,我们直接看代码和图:

nums = [1, 2, 3, [4, 5]]
nums_copy = nums[:]
print(id(nums))
print(id(nums_copy))

# 输出
# 2695619174984
# 2695620417672

通过地址打印,首先我们可以确定的是,浅拷贝之后,列表变量 numsnums_copy 的指向已经不是同一个对象了,因为它们的地址不同

nums = [1, 2, 3, [4, 5]]
nums_copy = nums[:]
print(id(nums[0]))
print(id(nums_copy[0]))
print(id(nums[3]))
print(id(nums_copy[3]))

# 输出
# 140719115661056
# 140719115661056
# 2689543594504
# 2689543594504

接着我们打印了两个列表中的部分相同位置的元素,发现地址还是一样,这说明了,二者虽然已经是两个不同的列表对象,但它们的子对象仍然是相同的,现在我们尝试着修改其中一个列表的值,看看会有什么样有意思的事情发生:

nums = [1, 2, 3, [4, 5]]
nums_copy = nums[:]
nums[0] = 8
nums[3][0] = 100
print(nums)
print(nums_copy)

# 输出
# nums: [8, 2, 3, [100, 5]]
# nums_copy: [1, 2, 3, [100, 5]]

从打印信息看来,这里的子对象除了整数对象之外还有一个子列表对象,那么为什么整数对象的值没有更新,但子列表对象的值更新了呢?其实结合我们前面说到的 可变对象不可变对象 就很好理解:

4. 深拷贝

当您阅读到这里的时候,相信您已经对python的对象模型有了更加深刻的理解,深拷贝相较于浅拷贝唯一的区别就是我在介绍中说的那句话:深拷贝完全拷贝了父对象及其子对象

我们最后再走一遍流程,首先通过代码来看看深拷贝之后 nums 以及 nums_copy 的地址信息:


可以明显的看到经过深拷贝之后,不仅父对象的地址发生了变化,连子对象的地址也发生了变化,这表明了二者已经没有了任何交集,是两个彻底不同的对象。在这种情况下,我们再去修改 nums 的值,不会对 nums_copy 产生任何的影响:


那么它们在内存中的分配示意图应该是这样的:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容