下面有段代碼(以下簡稱測試?yán)樱┗肽龋隳茉诓豢创鸢盖闆r下知道運(yùn)行結(jié)果嗎佑力?
a = 1
b = 1
print(a is b) # True
print(a == b) # True
a = 10000
b = 10000
print(a is b) # 有時(shí)True 有時(shí)False
print(a == b) # True
a = -6
b = -6
print(a is b) # 有時(shí)True 有時(shí)False
print(a == b) # True
a = [1, 5]
b = [1, 5]
c = a
print(a is b) # False
print(a == b) # True
print(c is a) # True
print(c == a) # True
print(c is b) # False
print(c == b) # True
概念
在 Python 中,is
和 ==
都用于比較筋遭,是分別根據(jù)對象的內(nèi)存地址和對象的值來判斷打颤,所以用途上也不一樣暴拄。
用圖書館的書籍可以打個(gè)值和內(nèi)存地址形象的比喻:
- 對象的值,就像書籍內(nèi)容:
- 每本書都有它的內(nèi)容编饺,例如文字乖篷、圖片等,這代表了書的“值”透且。
- 不同的書可能有相同的內(nèi)容(例如兩本相同的書)撕蔼,但它們?nèi)匀皇遣煌膶?shí)體。
- 對象的內(nèi)存地址秽誊,書籍在圖書館中的位置:
- 每本書在圖書館中都有一個(gè)特定的位置鲸沮,比如在某個(gè)書架的某一層某一排。
- 即使兩本書的內(nèi)容完全相同锅论,如果它們在不同的位置上讼溺,它們就是兩個(gè)不同的對象。
is 身份運(yùn)算符
is 用于比較兩個(gè)對象的身份最易,即比較兩個(gè)對象在內(nèi)存中的地址(內(nèi)存地址可以用Python內(nèi)建函數(shù)id()
查看肾胯,它會返回一個(gè)整數(shù))是否相同。換句話說耘纱,它檢查的是兩個(gè)對象是否是同一個(gè)對象敬肚。
回到開頭測試?yán)永铮?/p>
# 注意:以下id函數(shù)計(jì)算出的內(nèi)存地址整數(shù)不一定是代碼的那些整數(shù)
a = 1
b = 1
print(id(a), id(b)) # 輸出:2398302306544 2398302306544
print(a is b) # True,因?yàn)閍和b的id內(nèi)存地址相同束析,所以a和b是同一個(gè)對象
a = [1, 5]
b = [1, 5]
print(id(a), id(b)) # 輸出:2398357892288 2398357883648
print(a is b) # 輸出: False艳馒,因?yàn)閍和b的id內(nèi)存地址不同,所以a和b是不同的對象员寇,即使它們的值相同
c = a
print(id(a), id(c)) # 輸出:2398357892288 2398357892288
print(a is c) # 輸出: True弄慰,因?yàn)閏和a的id內(nèi)存地址相同,所以c和a是同一個(gè)對象
== 比較運(yùn)算符
==
用于比較兩個(gè)對象的值是否相等蝶锋。它檢查的是對象的值
是否相同陆爽,而不是對象本身是否相同(雖然拗口,但事實(shí)如此)扳缕。 這意味著即使是兩個(gè)不同的對象慌闭,只要它們的值相同,== 比較的結(jié)果就是 True躯舔。
a = 1
b = 1
print(a == b) # 輸出: True驴剔,因?yàn)?a 和 b 的值相同
a = [1, 5]
b = [1, 5]
c = a
print(a == b) # 輸出: True,因?yàn)?a 和 b 的值相同
print(c == b) # 輸出: True粥庄,因?yàn)?c 和 b 的值相同
通常情況下丧失,==
可以通過重載 __eq__
方法來定義值比較行為, 再舉回書籍的例子,我們用書籍內(nèi)容content
來表示對象的值惜互,location
不是內(nèi)存地址
class Book:
def __init__(self, location, content):
self.location = location
self.content = content
def __eq__(self, other):
if isinstance(other, Book):
return self.content == other.content
return False
def __repr__(self):
return f"Book(content='{self.content}')"
# 創(chuàng)建兩個(gè) Book 對象
book1 = Book(location="A", content="Hello")
book2 = Book(location="B", content="Hello")
book3 = Book(location="C", content="Hi")
# 比較對象
print(book1 == book2) # 輸出: True布讹,因?yàn)?content 相同
print(book1 == book3) # 輸出: False琳拭,因?yàn)?content 不同
# 查看對象內(nèi)存地址,不同的對象
print(id(book1)) # 輸出: 1907430631760
print(id(book2)) # 輸出: 1907430632240
print(id(book3)) # 輸出: 1907430632336
注意
共用緩存對象
你也許發(fā)現(xiàn)了is
在某些情況下判斷并不穩(wěn)定描验,比如測試?yán)又?code>a白嘁、b
都等于10000
(或-6
)時(shí),a is b
有時(shí)候會等于False
挠乳,有時(shí)候會等于True
。
這主要是因?yàn)?code>Python對于一些小整數(shù)(通常在-5
到256
之間姑躲,范圍并不是固定)和一些字符串進(jìn)行了緩存睡扬,所以這些對象在內(nèi)存中會被重用。 當(dāng)比較這些小整數(shù)和字符串時(shí)黍析,is
比較時(shí)可能返回 True
卖怜,即使你認(rèn)為它們是不同的對象。
所以涉及到這些對象進(jìn)行比較時(shí)阐枣,一般不用is
而是==
马靠。
單例模式
在單例模式下,所有構(gòu)造出來的對象實(shí)際上都是同一個(gè)實(shí)例蔼两,因此使用 is
和 ==
進(jìn)行比較時(shí)甩鳄,結(jié)果都應(yīng)該是 True
,但一般都是用is
來判斷额划。
這是因?yàn)槭褂?is
來判斷更加直觀和高效妙啃, is
比較的是對象的身份(即內(nèi)存地址),而 ==
比較的是對象的值俊戳,要先找到地址才能找到值揖赴,而且某些值比較時(shí)需要進(jìn)行額外計(jì)算消耗資源(參考找書籍的例子)。
在python中有些比較特殊的對象如None
抑胎、True
燥滑、False
等,它們都是個(gè)單例對象阿逃,所以通常判斷一個(gè)變量是否為這些對象時(shí)應(yīng)該使用 is
而不是 ==
铭拧。
應(yīng)用場景
-
is
主要用于判定是不是同一個(gè)對象,在與單例對象比較時(shí)恃锉,一般都是有is
來判斷 -
==
通常是用于兩個(gè)對象確切的值的比較羽历,比如字符串比較,數(shù)值比較淡喜。
總結(jié)
-
==
:比較兩個(gè)對象的值是否相等秕磷。 -
is
:比較兩個(gè)對象的身份(內(nèi)存地址)是否相同。