可变类型与不可变类型及其赋值、浅拷贝与深拷贝

可变类型与不可变类型

python变量可以分为两种:可变类型与不可变类型
其中:
不可变类型:数字、字符串、元祖、不可变集合
可变类型:列表、字典、集合、可变集合

每当python声明一个变量,它都以对象的形式存在内存中,可以理解为变量名为对象的指针

1.1 不可变类型的特点

当声明param=1时,则param指向存储1的空间。同时,python使用计数器的方式来判断空间的引用情况,当计数器为0时,会将内存回收。

python在声明不可变类型时,会在已经声明的对象中去寻找该对象是否已经被声明过,若该对象被声明过,变量会直接指向该对象而不会在申请新的内存空间。

(1). 相同值变量指向同一块内存地址
例如,对于数字型变量:

a = 3
b = 3
a is b
True

a 与 b都为不可变类型,当声明b变量时,由于和a相同已经被声明过,则a、b指向同一块内存
(2). 不可对其值直接修改
例如,对于字符串型变量,同样为不可变类型

str_test = "haohaoxuexi"

不可对字符串中某个字母进行替换
在这里插入图片描述
替换报错:
在这里插入图片描述
但是,可以对其进行切割或加长处理:
加长处理:
在这里插入图片描述
切割:
在这里插入图片描述
不是在原有内存中存储的字符串值进行改变,本质上是将新的字符串存储到新的内存中

1.2 不可变类型的赋值、浅拷贝与深拷贝

import copy
a = (1, 2)
b1 = a
b2 = copy.copy(a)
b3 = copy.deepcopy(a)

在这里插入图片描述
对于不可变类型,赋值、浅拷贝和深拷贝的意义相同(或者说深浅拷贝无意义),毫无区别可言(也就是说不可变类型,无深浅拷贝),不同变量的同一个值,永远指向同一个地址。值相同,地址也相同,这些变量也就完全相同。

2.1 可变类型的特点

(1). 可变类型变量可以对其值进行修改:

a = [1, 2, 3]
a[0] = 888
a

结果:

[888, 2, 3]

在原有内存中存储的值进行修改,注意与不可变类型不可修改值进行区别,修改值时它不开辟新的内存空间
(2). 相同值变量可以指向同一内存地址,也可指向不同内存地址
可变类型比不可变类型变量要复杂,不可简单判断相同值变量的地址相同或不同,但一般按照如下进行分类分析:赋值、浅拷贝和深拷贝

2.2 可变类型的赋值、浅拷贝与深拷贝

(1). 对于赋值操作,相同值的变量指向同一内存地址
赋值操作不会开辟新的内存空间,而是将a的引用赋给b,a与b指向同一内存地址

例如,对于列表型变量,为可变变量:

a = [1, 2, 3]
b = a

a is b

结果:
在这里插入图片描述
变量都是以指针的形式存在,赋值操作其实是将指向的对象进行改变,并不是改变了内存中的内容
(2). 对于浅拷贝,变量部分指向不同地址,变量的第一层值指向不同地址,而深层指向同一地址
浅拷贝会分配新的内存地址,该地址与原对象( 变量 )地址不是完全不同,而是父对象地址不同,子对象地址相同;即只拷贝了对象的第一层,重新分配了内存地址,而对于深层,如第二层,没有进行拷贝,内存地址相同。

例1,对于简单单层列表型变量,为可变变量:

import copy

a = [1, 2, 3]
b = copy.copy(a)

print(a is b)
print(id(a), id(b))

结果:
在这里插入图片描述
没有子层,新变量直接整体开辟新地址

例2,对于嵌套列表变量:

a = [1, 2, 3, [4, 5, 6]]
b = copy.copy(a)

print(a is b)
print(id(a),id(b))
print("第一层:",a[0:3],id(a[0:3]),b[0:3],id(b[0:3]))
print("深层:",a[3],id(a[3]),b[3],id(b[3]))

结果:
在这里插入图片描述
可以看到:变量的值相同,第一层地址不同,但是子层地址相同
新变量第一层引用指向新地址,新变量子层引用指向原变量子层内存地址

(3). 对于深拷贝,变量整体指向不同的地址( 无论有无父子层 )
深拷贝拷贝了对象所有元素,包括多层嵌套的元素

import copy

a = [1, 2, 3, [4, 5, 6]]
b = copy.deepcopy(a)

print(a is b)
print(id(a),id(b))
print("第一层:",a[0:3],id(a[0:3]),b[0:3],id(b[0:3]))
print("深层:",a[3],id(a[3]),b[3],id(b[3]))

结果:
在这里插入图片描述
无论哪一层,内存地址都变了,新的拷贝变量拥有全新的地址

注意,下面的例子:

a = [1, 2, 3]
b = [1, 2, 3]

在这里插入图片描述
重新赋相同的值,也类似于深拷贝,会分配新的地址,a与b完全无关。

参考博客

python不可变类型和可变类型
赋值、浅拷贝、和深拷贝的区别

发布了45 篇原创文章 · 获赞 1 · 访问量 2440

猜你喜欢

转载自blog.csdn.net/weixin_44225602/article/details/102769513