python之可变对象和不可变对象详析

1.基本概念

1.1 变量

先理解python中的变量,再去理解对象便于理解。

  1. python中的变量都是指针,它指向任意对象。具体地说,因为变量是指针,所以所有的变量无类型限制,可以将变量的类型可以是整数型、浮点型、字符串、类等。
  2. 变量的内存空间大小是与类型无关的,其内存空间只是保存了所指向数据的内存地址。
    可以简单的理解为变量只是对象的名称,指向对象。

1.2 对象

理解完变量是对象的指针后,我们来理解对象。

  1. 对象即存储在内存空间的值。我们可以简单理解对象包括id(内存存储地址)、type(类型)、value(值)。
  2. 对象类型可分为不可变对象和可变对象。
  3. 可变对象是指当有需要改变对象内部的值的时候,这个对象的id不发生变化
  4. 不可变对象是当有需要改变对象内部的值的时候,这个对象的id会发生变化

2.可变对象

可变对象指的就是我们可以对对象里面的value进行改变,但id不变。包括:字典(dict), 集合(set), 列表(list)。

  • 通过变量去修改对象的值,这种操作不会改变变量所指向的对象。即id不变
a = [1,2,3]
print(a,id(a))  # 结果:[1, 2, 3] 2001285173640
a[0] = 10   # 通过变量去修改对象的值
print(a,id(a))  # 结果:[10, 2, 3] 2001285173640
# 这个操作时通过变量去修改对象的值
# 这种操作不会改变变量所指向的对象
  • 给变量重新赋值,即使是赋予一模一样的值,一定会改变变量所指向的对象。即id变化
a = [1,2,3]
print(a,id(a))  # 结果:[1, 2, 3] 1917428388232
a = [1,2,3] 
print(a,id(a))  # 结果:[1, 2, 3] 1917428388744
# 这个操作在给变量重修赋值
# 这种操作会改变变量所指向的对象
  • 一个变量赋予给另一个变量,指向的是同一个对象。即id值相同,并且一个变量通过变量去修改对象的值,则另一个变量的值也会发生变化,因为指向的是同一个对象中的值。但给一个变量重新赋值,则另一个变量值不发生变化,因为一个变量已经改变了对象
a = [1,2,3]
b = a
print('a的id',id(a))  # 结果:a的id 2365800141192
print('b的id',id(b))  # 结果:b的id 2365800141192
a.extend([4,5])
print(a,'a的id',id(a))  # 结果:[1, 2, 3, 4, 5] a的id 2365800141192
print(b,'b的id',id(b))  # 结果:[1, 2, 3, 4, 5] b的id 2365800141192
a = [1,2,3]
print(a,'a的id',id(a))  # 结果[1, 2, 3] a的id 1954530218888
print(b,'b的id',id(b))  # 结果:[1, 2, 3, 4, 5] b的id 2365800141192
# 变量赋值给另外一个变量是指向同一个内存中的对象的过程
# 通过变量去修改对象的值,另一个变量值也会发生改变
# 通过改变变量的赋值,另一个变量值也会不会改变
  • 原理示意图
    从上面的程序中可以看出,进行两次a = [1, 2, 3]操作,两次a引用的地址值是不同的,也就是说其实创建了两个不同的对象

我们对列表进行添加操作,分别a.append(4),发现作使得a引用的对象值改变,但是a引用的地址依旧是不变,也就是说对a进行的操作不会改变a引用的地址值,只是在地址后面又扩充了新的地址,改变了地址里面存放的值,所以可变数据类型的意思就是说对一个变量进行操作时,其值是可变的,值的变化并不会引起新建对象,即地址是不会变的,只是地址中的内容变化了或者地址得到了扩充。

在这里插入图片描述

3.不可变对象

不可变对象指的是我们对对象里面的value进行改变,则id会变。
Python中,数值(整型,浮点型),布尔型,字符串,元组属于不可变对象,本身不允许被修改,属于值类型。
数值的修改实际上是让变量指向了一个新的对象(新创建的对象),所以***不会发生共享内存问题***
注意:不可变对象的修改存在一些id变化差异。

3.1 int类型

  • int值比较小时,值一样的变量id就一样,值变化id就变化。
    在这里插入图片描述
  • int 值比较大时,值一样的变量id也不一样,值变化id就变化。
    在这里插入图片描述
  • 总结

python中较小的整数会频繁的被使用,所以python将这些对象放置到了一个池子中,每次需要这些对象的时候就到池子中获取这个值,避免多次的重复创建对象引起的许多不必要的开销。
这个池子内的数字范围是[-5, 257), 所以都是从池子里面取值,自然id不变。
而对于超过这个数字范围的数字id都不一样。

3.2 float类型

  • float 值一样的变量id也不一样,值变化id就变化
    在这里插入图片描述
  • 总结
    对于float类型的使用没有int那么频繁,并且float类型也不好定义哪些常用,也就没有池子给到这个类型,所以每次重新创建即可。

3.3 tuple类型

tuple 值一样的变量id也不一样
在这里插入图片描述

  • 总结
    原理同float类型相似

3.4 str类型

  • 单词类型的 str 类型的值一样的变量id都相同,值变化的id就变化
    在这里插入图片描述
  • 非单词类型的str 值一样, 变量的id也不相同。
    在这里插入图片描述
  • 总结
    python中考虑到单词类型的str被重复使用的概率比较大,所以在python中为单词类型的str做了一个缓存,也就是说如果是单词类型的str,会被存储到一个字典(dict)中,字典的内容是字符串为key, 地址为value
    当有一个字符串需要创建,就先去访问这个字典,如果存在则返回字典中字符串的地址,如果不存在,则返回新创建的地址,并将这个字符串添加进入字典。这是字符串的intern机制。

本文参考的博主链接有:
1.Python3之可变对象和不可变对象
2.Python中的不可变对象类型与可变对象类型

发布了11 篇原创文章 · 获赞 0 · 访问量 331

猜你喜欢

转载自blog.csdn.net/Claire_chen_jia/article/details/105668807