首页 > 技术文章 > python中深浅拷贝

zylwy 2020-12-04 19:37 原文

首先要了解什么是深浅拷贝,我们就要知道一个知识点:什么是可变类型?什么是不可变类型

"""

不可变类型:当改变值得时候,会申请一块新的内存空间,不再是原来的那一块内存空间。

而整数类型、浮点型、字符串、元组、布尔类型都是不可变类型。

例如:

>>> a = 1

>>> print(id(a))

2282593282352

>>> a = 2

>>> print(id(a))

2282593282384

>>> a = "佩奇"

>>> print(id(a))

2282595304144

>>> a = 1.23

>>> print(id(a))

2282593912240

>>> a = (1,2)

>>> print(id(a))

2282595316608

>>> a = True

>>> print(id(a))

140712455141480

>>>他们的id地址都是不一样的,所以整数类型、浮点型、字符串、元组、布尔类型都是不可变类型。

可变类型:就是这个数据类型的值在不改变这一块内存空间前提下,而去改变这个数据类型的值。

而列表类型和字典类型就是可变类型

例如:列表类型

>>> a = ["佩奇","年龄",18]

>>> print(id(a))

2286422249792

>>> a[0]="乔治"

>>> print(a)

['乔治', '年龄', 18]

>>> print(id(a))

2286422249792

>>>在列表中将佩奇换成乔治,id地址没有发生变化zi

例如:字典类型

>>> a = {"name":"佩奇","age":18}

>>> print(id(a))

1625026357248

>>> a["name"] = "乔治"

>>> print(a)

{'name': '乔治', 'age': 18}

>>> print(id(a))

1625026357248

>>>在在列表中将佩奇换成乔治,id地址没有发生变化

"""

了解了什么是可变类型,什么是不可变类型,接下来就是我们要讲的重点python中的深浅拷贝

"""

浅拷贝:

浅拷贝就是把原列表第一层的内存地址不加区分的完全copy一份给新列表,简单来说就是拷贝了一下原列表产生了一个新的列表。

例如:

>>> a = ["佩奇",18,["乔治",16]]

>>> b = a.copy()

>>> print(b)

['佩奇', 18, ['乔治', 16]]

>>> print(id(a))

1621358543552

>>> print(id(b))

1621358543616

>>>虽然id地址发生了变化,但是仅仅只是a,b列表整体id地址发生了变化,也就是第一层的内存地址变了,但是a,b列表内部的id地址并没有发生变化

如下我们查看“佩奇“,18,['乔治', 16],的id地址

>>> print(id(a[0]),id(a[1]),id(a[2]))

1621358494416 1621356473168 1621358268608

>>> print(id(b[0]),id(b[1]),id(b[2]))

1621358494416 1621356473168 1621358268608

>>>

这样的话,如果我们改变a列表的值,b列表的值会不会改变

例如:

>>> a[0] = "哥哥"

>>> a[1] = 20

>>> a[2][0] = "弟弟"

>>> a[2][1] = 18

>>> print(a)

['哥哥', 20, ['弟弟', 18]]

>>> print(b)

['佩奇', 18, ['弟弟', 18]]

>>>我们发现字符串类型和整数类型不会改变,但是列表类型里面的值发生了改变

总结:浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是原对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素( 新瓶装旧酒 )。浅拷贝中,不可变类型不会随着原列表的变化而变化,但是可变量类型,列表、字典会跟着原列表的变化而变化。

"""

所以想要copy得到新列表与原列表的改操作完全独立开,必须有一种可以区分开可变类型与不可变类型的copy机制,这就是深拷贝

深拷贝:

完全拷贝了一个副本,容器内部元素地址都不一样

"""

首先我们需要导入一个模块copy,有一个deepcopy功能

举例说明:

>>>import copy

>>>a = ["佩奇",18,["乔治",16]]

>>>b = copy.deepcopy(a)

>>>print(b)

['佩奇', 18, ['乔治', 16]]

>>>print(id(a))

1817894894656

>>>print(id(b))

1817894892864

接下来改变a列表的值,看b列表中的可变类型是否发生变化

>>> a[0] = "哥哥"

>>> a[1] = 20

>>> a[2][0] = "弟弟"

>>> a[2][1] = 18

>>> print(a)

['哥哥', 20, ['弟弟', 18]]

>>> print(b)

['佩奇', 18, ['乔治', 16]]

"""

总结:深拷贝是将两个列表完全独立开,在另一块地址中创建一个新的容器,同时容器内的元素的地址也是新开辟的,仅仅是内容相同而已,是完全的副本。也就是说( 新瓶装新酒 )。所以想要copy得到新列表与原列表的改操作完全独立开,新列表的内容完全不受原列表的影响,就需要用深拷贝。

推荐阅读