a ="Hi"
b = "Hi"
a is b
True
is
和 ==
结果一样:
a == b#is和==结果一样
True
al = "I am using long string for testing"
bl ="I am using long string for testing"
al is bl#is 的结采为 False
False
al == bl#
True
str1 = "string"
str2 = "" . join(['s','t','r','i','n','g'])
print (str2)
string
str1 is str2
False
==
和 is
的结果在这种情况也不一样:
str1 == str2 #==和is的结果在这种情况也不一样
True
造成这种奇怪现象的原因是什么呢?为什么在有些情况下 is
和 ==
输出相同而在有些情况下又不相同呢?
分析一下:首先通过 id()
函数来看看这些变量在内存中具体的存储空间,为了方便讨论问题,
用表2-1来表示上例具体结果。
表2-1不同变置组 id()
以及 is
和 ==
的求值结果
id() | is | == | |
a = "Hi"① | 14085224 | True | True |
b = "Hi"① | 14085224 | ||
a1 = "I am using long string for testing"② | 13003368 | False | True |
b1 = "I am using long string for testing"② | 14078152 | ||
str1 = "string" | 13256448 | False | True |
str2 = "" . join(['s','t','r','i','n','g']) | 14056544 |
从表格中可以清晰地看到,is
和 ==
在验证两个字符串是否相等的时候表现确实不一致, 显然混用或者将它们等同起来是存在风险的。
那么字符串的比较到底是用 is
还是用 ==
呢? 先来看看Python官方文档中对这两种操作的如下所示。
is
:object identity
==
:equal
is
表示的是对象标示符(object identity ),而 ==
表示的意思是相等(equal ),显然两者不是一个东西。
实际上,造成上面输出结果不一致的根本原因在于: is
的作用是用来检査对 象的标示符是否一致的,
也就是比较两个对象在内存中是否拥有同一块内存空间,它并不适合用来判断两个宇符串是否相等。
x is y
仅当 x
和 y
是同一个对象的时候才返回 True
, x is b
基本相当于 id(x) == id(y)
。
而 ==
才是用来检验两个对象的值是否相等的,它实际调用内部 _eq_()
方法,
因此 a == b
相当于 a._eq_(b)
,所以 ==
操作符是可以被重载的,而 is
不能被重载。
一般情况下,如果 x is y
为 True
的话 x==y
的值也为 True
(特殊情况除外,
如 NaN
, a = float('NaN')
; a is a 为 True, a=a 为 false)
,反之则不然。
弄淸楚了 is
和 ==
之间的区别,再来看上述表格中的输出也就不难理解了。
但如果再细 心一点也许会发现第1组(标注①)中a
和b
的id值一样,也就是说它们在内存中是同一个对象,
而第二组(标注②)中a1
和b1
的id值却不一样。这又是为什么呢?
这是Python中的 string interning
(宇符串驻留)机制所决定的:
对于较小的字符串,为了提高系统性能会保留其值的一个副本,当创建新的字符串的时候直接指向该副本即可。
因此标注①中“Hi”在系统内存中实际上只有一个副本,所以a
和b
的id值是一样的;
断标注②中a1
和b1
是长字符串,并不会驻留,Python内存中各自创建了对象来表示a1
和b1
,
这两个对象拥有相同的内容但对象标示符却不相同,所以 ==
的值为True而的值为 False
。
注意:判断两个对象相等应该使用 ==
而不是 is
。