1、可变类型
值改变,id不变,证明改的是原值,证明原值是可以被修改的。
可变类型有:list、dict
验证
list
# 修改前
li = ['aaa', 'bbb', 'ccc']
print(li) # ['aaa', 'bbb', 'ccc']
print(id(li)) # 1534124489600
# 修改后
li[0] = 'AAA'
print(li) # ['AAA', 'bbb', 'ccc']
print(id(li)) # 1534124489600
dict
这里争对了字典的补充,原先我们说{}号内用逗号隔开key:value的形式,key唯一,通常(99%的情况下,字典的key都是字符串)为字符串类型(因为字符串具有描述性),值可以是任意类型。
之前所说的key通常为字符串类型,完整的说字典的key必须是不可变类型,下面用了4种不可变类型举例(int,float,bool,str):
# 修改前
dic = {100: 'int', 'AAA': 'str', True: 'bool', 3.14: 'float'}
print(dic) # {100: 'int', 'AAA': 'str', True: 'bool', 3.14: 'float'}
print(id(dic)) # 1443792249408
# 修改后
dic[100] = 'int-100'
print(dic) # {100: 'int-100', 'AAA': 'str', True: 'bool', 3.14: 'float'}
print(id(dic)) # 1443792249408
2、不可变类型
值改变了,id也变了,证明是产生新的值,压根没有改变原值。
不可变类型有:int、float、str
验证
int
# 修改前
x = 10
print(id(x)) # 140715012507584
# 修改后,下面使用了变量赋值、以及增量赋值2种修改方式
x = 20
print(id(x)) # 140715012507904
x += 20
print(id(x)) # 140715012508544
float
# 修改前
x = 10.3
print(id(x)) # 1818265421872
x = 20.3
# 修改后,下面使用了变量赋值、以及增量赋值2种修改方式
print(id(x)) # 1818264232976
x += 20.3
print(id(x)) # 1818265422256
str
# 修改前
x = 'aaa'
print(id(x)) # 1614906980528
# 修改后
x = 'AAA'
print(id(x)) # 1614906972400
bool
# 修改前
x = True
print(id(x)) # 140715012228944
# 修改后
x = False
print(id(x)) # 140715012228976
总结:
int、float、str、bool都被设计成了不可分割的整体,不能够被改变
3、可变类型与不可变类型的值修改的底层原理
可变类型
可变类型,像list这种容器类型,修改的是容器里面的值,而并不是对容器本身的修改,对容器本身的修改,id肯定会变化。我们所知列表是索引取值,容器中是有索引映射值得内存地址,当我们修改值时,修改得其实是值得内存地址,容器类型本身得内存地址并不会发生变化,所以id查看修改后的内容时,该列表对于于内存中得id编号并不会发生改变。
不可变类型
不可变类型,像int整型,举个例子:先age=18,后age=19,前者值18的内存空间对于变量名age,当执行到后者age=19时,会开辟一个新的内存空间(这里忽略python解释器自带的小整数池的这种优化机制),把值19放到堆区,栈区中age映射到值19的内存地址的位置,这个时候就与值18的内存地址映射关系断开,而值19这个新开辟出来的内存地址当然于值18的内存地址不一样,所以说查看id时,id编号一定是不一致的,在这个过程中原值18并没有改变,这就是不可变类型。