小一点int类型相等
s = 1
r = 1 # id(s) == id(r) true
大一点的int类型就不一样了?
s = 1111111111
r = 11111111111 # id(s) != id(r)
所有测试的float类型都不相等
s = 1.1
r = 1.1
#id(s) != id(r)
所有测试的tuple类型都不相等
s = (1, 2)
r = (1, 2)
#id(s) != id(r)
所有测试的str都相等
s = 'aaaa'
r = 'aaaa'
#id(s) == id(r)
不是应该都复用相同的不可变对象用以节约内存吗?
回答:
<Python源码剖析>上解释的很清楚:
Python里一切都是对象.所以1,2,3,4...这些整数也都是对象.这些基本的不可变对象在python里会被频繁的引用,创建,如果不找到好的办法的话很容易让python引发效率瓶颈,所以python引入了整数对象池的机制.
intobject.c中代码片段
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS 257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS 5
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
/* References to small integers are saved in this array so that they
can be shared.
The integers that are saved are those in the range
-NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endif
作者:知乎用户
链接:https://www.zhihu.com/question/25050656/answer/34717037
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- int清楚写了[-5, 256] 这些小整数被定义在了这个对象池里.所以当引用小整数时会自动引用整数对象池里的对象的.
- string对象也是不可变对象,python有个intern机制,简单说就是维护一个字典,这个字典维护已经创建字符串(key)和它的字符串对象的地址(value),每次创建字符串对象都会和这个字典比较,没有就创建,重复了就用指针进行引用就可以了.
string实现了intern共享?我觉得是一种空间效率和时间效率的妥协。相比于数字,string本身参与的运算要少很多,而且string本身占据的空间也大许多,因此string的主要问题在于不共享带来的空间浪费,所以string实现了很费时间的intern操作。对于数字情况正好相反。作为一个数字,需要做的运算要比string多太多了,而且大小比string也小很多。如果在计算10000+20000之前先花好久查找重复对象,导致一个1ms完成的加法花了100ms,我肯定想砸电脑的。
- float类型可以认为每个赋值都是创建一个对象,因为float有点多,所以没必要和int一样了.
- tuple它是不可变对象,理应和int和string一样会做一个缓存,但是书上没有说明,于是看了看源码,发现tuple的数据结构很简单,简单到不能再简单,就是一个数组,里面是元组的迭代对象,这个对象指向的是各个元素.最关键的是元组没有实现intern机制!所以元组虽然是不可变对象,但它同时也是一个数组,这个数组和c里的数组一样,每次创建都会分配内存空间。