本文同步發表於 Prodesire 公衆號和 Prodesire 博客。html
Python 的 "is" 和 "==" 想必你們都不陌生,咱們在比較變量和字面量時經常用到它們,但是它們的區別在哪裏?什麼狀況下該用 is
?什麼狀況下該用 ==
?這成了很多人心中的困惑。python
當咱們判斷一個變量是否爲 None
時,一般會用 is
:緩存
>>> a = None >>> a is None True >>> b = 1 >>> b is None False
而當咱們判斷一個變量是否爲字面量(好比某個數值)時,一般會用 ==
:ide
>>> a = 0 >>> a == 0 True >>> a == 1 False
要想解決上面的疑惑,咱們首先須要搞明白 is
和 ==
是什麼。code
is
用來檢查身份(identity)的同一性,即兩個變量是否指向同一個對象。htm
==
用來檢查值的相等性(equality),即兩個變量的值是否相等。對象
身份的同一性同時也意味值的相等性,既然兩個都指向同一個對象,那值就確定相等。可是反之則不是。ci
既然 ==
是用來檢查值的相等性,那麼兩個對象的值比較到底是怎麼進行的?字符串
對於基本類型的對象的值比較,咱們很容易理解。好比列表對象 [1, 2, 3] 的值比較就是比較列表的長度和列表中每一個元素的值。get
可是對於自定義的對象,該如何進行值比較?這裏就涉及到了 __eq__(self, other)
魔法方法,咱們能夠經過該方法來實現對象的 ==
邏輯。好比:
>>> class Foo(object): ... def __eq__(self, other): ... return True ... >>> foo = Foo() >>> foo == 1 True >>> foo == None True >>> foo is None False
在上面的示例中,咱們定義了 Foo
類,並實現了 __eq__(self, other)
方法,它永遠返回 True
,也就意味着和任何對象作值比較(==
)結果都是 True
。而當它作同一性比較時,好比和 None
比較,因爲不是同一個對象,因此返回 False
。
>>> a = [1, 2, 3] >>> b = a # b 指向 a,a 指向 [1, 2, 3],因此 b 指向同一個 [1, 2, 3] >>> b is a True >>> b == a True
在上述示例中 a
和 b
均指向同一個列表對象 [1, 2, 3]
,因此對它們使用 is
和 ==
,結果都是 True
。
>>> a = [1, 2, 3] >>> b = a[:] # b 複製了一份 a 所指向的列表,產生新的 [1, 2, 3] >>> b is a False >>> b == a True
在上述示例中,因爲 b
指向的是 a
的副本,也就是說 a
和 b
指向兩個不一樣的對象,因此對它們使用 is
的結果是 False
。但因爲值相等,使用 ==
的結果就是 True
。
>>> a = 256 >>> b = 256 # 和 a 指向同一字面量 256 >>> a is b # 代表指向同一對象 True >>> a == b True >>> >>> a = 257 >>> b = 257 >>> a == b True >>> a is b # 代表指向不一樣對象 False >>>
一般來講,兩個變量指向字面量,它們的比較應該使用 ==
,而非 is
,不然就可能有相似上述示例中的困惑。
在 Python 的交互解釋器中,把可能頻繁使用的整數對象規定在範圍 [-5, 256]
之間,當它們建立好後就會被緩存下來。但凡是須要再用到它們時,就會從緩存中取,而不是從新建立對象。
a
和 b
都指向同一個字面量 256
時,a is b
返回 True
。這是由於聲明 b = 256
時,256
整數對象是從緩存中取的,而非從新建立,因此 a
和 b
指向同一個整數對象。a
和 b
都指向同一個字面量 257
時,a is b
返回 False
。這是由於聲明 b = 257
時,257
整數對象沒被緩存,是從新建立的,因此 a
和 b
指向不一樣的整數對象。同理,若是字面量是字符串,結果也相似。
>>> a = 'python.org' >>> b = 'python.org' >>> a is b False >>> a == b True >>> a = 'pythonorg' >>> b = 'pythonorg' >>> a is b True >>> a == b True
is
比較字面量時報 SyntaxWarning鑑於使用 is
比較字面量實際上是不正確的,在 Python 3.8 的 release notes 中,引入以下內容:
> The compiler now produces a SyntaxWarning when identity checks (is and is not) are used with certain types of literals (e.g. strings, numbers). These can often work by accident in CPython, but are not guaranteed by the language spec. The warning advises users to use equality tests (== and !=) instead. (Contributed by Serhiy Storchaka in bpo-34850.)
所以,當咱們使用 is
去比較數字、字符串等字面量時,就會報 SyntaxWarning
:
>>> x = 200 >>> x is 200 Traceback (most recent call last): File "<stdin>", line 1, in <module> SyntaxWarning: "is" with a literal. Did you mean "=="?
說了這麼多,其實咱們只須要記住以下兩點:
==
。is
。