以下代码均在 win64位电脑 python3.6解释器中运行
说到基础数据类型,我们可以很容易的想到 数字 字符串 元组……
我们都知道数字int 是不可变数据类型,也就是每一个数字都会开辟一块内存空间进行存储数据。
>>> id(1)
499664528
>>> id(2)
499664544
>>> id(3)
499664560
>>> id(4)
499664576
id()理解成内存地址 可以发现一个规律 对于整数 每隔16个空间开辟一个内存,可以预测下一个的内存地址是499664592
>>> id(5)
499664592
这个规律真的可以适用于所有整数么?
>>> id(400)
31145456
>>> id(401)
31145488
>>> id(402)
31145504
>>> id(403)
31145440
可以发现完全没有什么规律可言,
当我们用终端 重新开启一个python解释器
>>> id(400)
17382768
>>> id(401)
17382896
>>> id(402)
17382880
>>> id(403)
17382912
可以发现是随机开辟内存进行数据的存储的,那么为什么1 2 3这些数字是固定的内存地址,并且有规律可循呢?
原来python 为优化速度,对整数进行了优化,创建了一个小数据池, 避免为整数频繁申请和销毁内存空间。Python 对小整数的定义是[-5, 256]这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,无论这个整数处于LEGB中的哪个位置,所有位于这个范围内的整数使用的都是同一个对象。同理,单个字母也是这样的。
我们使用pycharm进行测试
print(id(1))
print(id(2))
print(id(3))
print(id(4))
print(id(256))
490882704
490882720
490882736
490882752
490886784
print(id(257))
print(id(258))
7093680
7093696
print(id(400))
print(id(401))
print(id(402))
7093712
7093744
7093760
多次运行记录结果
490882704
490882720
490882736
490882752
490886784
47136176
47136192
47136208
47136240
47136256
可以发现 [-5,256]是固定的 而 在pycharm中 进行了优化 :终端是每次执行一次,所以每次的大整数都重新创建,而在pycharm中,每次运行是所有代码都加载都内存中,属于一个整体,所以:这个时候会有一个大整数对象池,即处于一个代码块的大整数是同一个对象.
我们都知道了变量是存储着指向对象的内存地址,并不是对象的值
>>> a = 400
>>> id(a)
17382928
>>> id(400)
17382768
但是,对于[-5,256]之间的数
>>> a = 1
>>> id(a)
490882704
>>> id(1)
490882704
python内部对小数据池进行了优化,变量和值的内存地址是相同的。这只是优化后的结果,和变量并不冲突,因为对于[-5,256]之间的数,是永远存在于内存中的,并不是临时开辟一块空间进行存储。变量是存储了指向对象的内存地址。
我的理解就是变量对于静态对象,存储的是内存地址而不是存储一个多此一举的指向
字符串和数字相同,我们来看下列表
>>> id([1,2])
58017552
第二次执行
52090480
可以发现对于列表并不存在数据池的概念,也就是每一次创建列表都会重新开辟一块内存空间。
对于列表,内部实现了_ _ iadd_ 方法 和 add _ 方法,一个是就地增,一个是添加,来一起看看有什么区别
首先要知道: 如果没有实现 _ iadd _ 方法 进行 + 运算 会继续调用 _ _ add _ _方法,如果双下 add 方法也没有则会报错
>>> a = [1]
>>> id(a)
58017712
>>> a += [2]
>>> a
[1, 2]
>>> id(a)
58017712
>>> a = a + [3]
>>> id(a)
58017632
>>> a
[1, 2, 3]
结果应该十分明了, 对于就地加 并没有 开辟新的空间 ,而 添加 则 重新开辟了一块内存空间,又进行赋值运算
由此可以更好的理解,为什么 int,str,bool,tuple 叫做不可变数据类型,而 list,dict叫做可编数据类型了,
因为不可变数据类型均未实现双下iadd 方法,可能会有疑问 我们天天写 a += 1 ,因为 int类型没有实现双下iadd方法, 但是实现了 双下add方法 因此可以这样写,而想bool tuple 双下add 双下iadd 方法均未实现,所以更不可变
id(1000)
a=1000
id(a)
a = 1000
id(a)
三个id的值有不同
1000
a=1000
a = 1000
首先先明确:= 运算符先运算右边,所以 a = 1000 必然会先开辟空间存储 1000 这个数字,然后再把它赋给左边
这里是开辟了3个内存空间:第一个id(1000)时,开辟了一块内存空间,第一个赋值开辟了一个内存空间进行存储,而当第二个赋值的时候,又开辟了一块内存空间,所以这三个1000 是开辟了3个不同的内存空间进行存储,所以三次打印的id不同