Value的比较符号用双等号“==”,上例中比较l1和l2的Value要写成“l1 == l2”,明显两者的Value是相等的。按照约定俗成的习惯,我们把Value值相等的两个对象称为“相等”,而把Id值相等的两个对象称为“相同”。
所以,准确地说,上例的l1与l2相等,但是他们不相同,l1==l2,但l1 is not l2。
特权种族:共用内存的对象
每个对象被创建出来的时候,就会确定其Id标识,也就是给它分配内存地址。通常来说,新对象的内存地址也是新的,会从未分配的可用地址中取。
但是,为了提高内存利用效率,对于一些常用的对象,如一些数值较小的数字对象、布尔值对象、None对象、较短的字符串对象等等,python采取共用对象内存的分配策略。
# 新分配内存地址的例子
ww=[1,2]
ee=[1,2]
id(ww)==id(ee) >>>False
a=2018
b=2018
id(a)==id(b) >>>False
# 共用内存地址的例子
a=100
b=100
id(a)==id(b) >>>True
f1=True
f2=True
id(f1)==id(f2) >>>True
n1=None
n2=None
id(n1)==id(n2) >>>True
s="python_cat"
t="python_cat"
id(s)==id(t) >>>True
这就意味着,python中出现了“特权种族”,运行环境早早就为它们分配好了内存地址,一旦要创建新的对象时,先去特权种族中查找,有Type和Value相等的对象,则新对象不分配新的内存空间,而是指向已有对象。
“特权种族”的存在,使得我们不需要频繁创建这些对象,既能提高已分配内存的使用率,又减少了创建对象、分配新内存的损耗。
对于共用内存地址的数字对象的取值范围,根据这篇文章《Python中神秘的-5到256》(链接见文末)对python源码的分析,文中有如下结论:
Python中,对于整数对象,如果其值处于[-5,256]的闭区间内,则值相同的对象是同一个对象。
对于共用内存地址的字符串对象的取值范围,学习了几篇对python源码分析的文章后(链接见文末),猫猫总结出大致有以下结论:
Python中,字符串使用Intern机制实现内存地址共用,长度不超过20,且仅包括下划线、数字、字母的字符串才会被intern;涉及字符串拼接时,编译期优化结果会与运行期计算结果不同。
# 编译对字符串拼接的影响
s1 = "hell"
s2 = "hello"
"hell" + "o" is s2 >>>True
s1 + "o" is s2 >>>False
# "hell" + "o"在编译时变成了"hello",
# 而s1+"o"因为s1是一个变量,在运行时才拼接,所以没有被intern