Python中的赋值、浅拷贝、深拷贝介绍,python语言特点选择题

来源:未知 浏览 109次 时间 2021-06-10 21:34

和很多语言一样Python中也分为简单赋值、浅拷贝、深拷贝这几种“拷贝”方式。

在学习过程中一开始对浅拷贝理解很模糊。不过经过一系列的实验后分析SEO教程一开始对浅拷贝理解很模糊。不过经过一系列的实验后我发现对这三者的概念有了进一步的了解。

Python中的赋值、浅拷贝、深拷贝介绍

赋值算是这三种操作中最常见的了我们通过一些例子来分析下赋值操作:

str例
代码如下:
a = ‘hello’
b = ‘hello’
c = a
[id(x) for x in a,b,c]
[4404120000, 4404120000, 4404120000]

Python中的赋值、浅拷贝、深拷贝介绍

赋值是系统先给一个变量或者对象(这里是’hello’)分配了内存然后再将地址赋给a, b, c。所以它们的地址是相同的。

list例
代码如下:
a = [‘hello’]
b = [‘hello’]
c = a
[id(x) for x in a,b,c]
[4403975952, 4404095096, 4403975952]

但是这种情况却不一样了a和b的地址不同。为何?

因为str是不可变的所以同样是’hello’只有一个地址但是list是可变的所以必须分配两个地址。

这时我们希望探究以上两种情况如果 修改值 会如何?

str例
代码如下:
a = ‘world’
[id(x) for x in a,b,c]
[4404120432, 4404120000, 4404120000]
print a, b, c
world hello hello

这时a的地址和值变了但是b, c地址和值都未变。因为str的不可变性a要重新赋值则需重新开辟内存空间SEO让我从零起步a要重新赋值则需重新开辟内存空间所以a的值改变a指向的地址改变。b, c由于’hello’的不变性不会发生改变。

list例
代码如下:
a[0] = ‘world’
[id(x) for x in a,b,c]
[4403975952, 4404095096, 4403975952]
print a, b, c
[‘world’] [‘hello’] [‘world’]

这时a, c的值和地址均改变但二者仍相同b不改变。由于list的可变性所以修改list的值不需要另外开辟空间SEO让我从零起步所以修改list的值不需要另外开辟空间只需修改原地址的值。所以a, c均改变。

在了解了以上的不同点之后我们就能很好地分析浅拷贝和深拷贝了。

我们均用list作为例子。

二、浅拷贝
代码如下:
a = [‘hello’, [123, 234]]
b = a[:]
[id(x) for x in a,b]
[4496003656, 4496066752]
[id(x) for x in a]
[4496091584, 4495947536]
[id(x) for x in b]
[4496091584, 4495947536]

Line3,4可以看出a, b地址不同这符合list是可变的应开辟不同空间。那浅拷贝就是拷贝了一个副本吗?再看Line5 – 8我们发现a, b中元素的地址是相同的。如果说字符串’hello’地址一致还能理解但是第二个元素是list地址仍一致。 这就说明了浅拷贝的特点只是将容器内的元素的地址复制了一份 。

接着我们尝试修改a, b中的值:
代码如下:
a[0] = ‘world’
a[1].append(345)
print ‘a = ‘, a, ‘\n\r’, ‘b = ‘, b
a = [‘world’, [123, 234, 345]]
b = [‘hello’, [123, 234, 345]]

a中第一个元素str改变但是b中未改变;a中第二个元素改变b中也改变。这就符合不可变的对象修改会开辟新的空间可变的对象修改不会开辟新空间。也进一步证明了 浅拷贝仅仅是复制了容器中元素的地址 。

三、深拷贝
代码如下:
from copy import deepcopy
a = [‘hello’, [123, 234]]
b = deepcopy(a)
[id(x) for x in a, b]
[4496066824, 4496066680]
[id(x) for x in a]
[4496091584, 4496067040]
[id(x) for x in b]
[4496091584, 4496371792]

深拷贝后可以发现a, b地址以及a, b中元素地址均不同。这才是完全 拷贝了一个副本 。

修改a的值后:
代码如下:
a[0] = ‘world’
a[1].append(345)
print ‘a = ‘, a, ‘\n\r’, ‘b = ‘, b
a = [‘world’, [123, 234, 345]]
b = [‘hello’, [123, 234]]

从Line4,5中可以发现仅仅a修改了b没有任何修改。 因为b是一个完全的副本元素地址均与a不同a修改b不受影响 。

总结:

1. 赋值是将一个对象的地址赋值给一个变量让变量指向该地址( 旧瓶装旧酒 )。

2. 浅拷贝是在另一块地址中创建一个新的变量或容器但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素( 新瓶装旧酒 )。

标签: 地址拷贝元素hello