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并没有改变,这就是不可变类型。