一文掌握 Python 中的 "is" 和 "=="

本文同步發表於 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" 和 "==" 是什麼

is 用來檢查身份(identity)的同一性,即兩個變量是否指向同一個對象。htm

== 用來檢查值的相等性(equality),即兩個變量的值是否相等。對象

身份的同一性同時也意味值的相等性,既然兩個都指向同一個對象,那值就確定相等。可是反之則不是。ci

__eq__ 魔法方法

既然 == 是用來檢查值的相等性,那麼兩個對象的值比較到底是怎麼進行的?字符串

對於基本類型的對象的值比較,咱們很容易理解。好比列表對象 [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

在上述示例中 ab 均指向同一個列表對象 [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 的副本,也就是說 ab 指向兩個不一樣的對象,因此對它們使用 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] 之間,當它們建立好後就會被緩存下來。但凡是須要再用到它們時,就會從緩存中取,而不是從新建立對象。

  • ab 都指向同一個字面量 256 時,a is b 返回 True。這是由於聲明 b = 256 時,256 整數對象是從緩存中取的,而非從新建立,因此 ab 指向同一個整數對象。
  • ab 都指向同一個字面量 257 時,a is b 返回 False。這是由於聲明 b = 257 時,257 整數對象沒被緩存,是從新建立的,因此 ab 指向不一樣的整數對象。

同理,若是字面量是字符串,結果也相似。

>>> a = 'python.org'
>>> b = 'python.org'
>>> a is b
False
>>> a == b
True
>>> a = 'pythonorg'
>>> b = 'pythonorg'
>>> a is b
True
>>> a == b
True

Python 3.8 引入 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

相關文章
相關標籤/搜索