資料比較是程式語言的基礎,但是各語言的用法和一些細節不太一樣。
像是在python中使用==
和is
都可以比對字串(或是!=
和is not
),但是一個是比對值,一個是比對記憶體位置。究竟要在何時使用呢?讓我們看下去。
在字串比較中,可以使用「==
」,但有時使用「is
」(或是用「!=
」和「is not
」),像是我們使用字串比較
a = "eyelash"
b = a
c = "eyelash"
print(a == b) #會是True
print(a == c) #會是True
print(a == c) #會是True
print(b == a) #會是True
會發現「==
」和「is
」完全沒有差異。那到底為什麼要分成兩種不同寫法呢?這時改用陣列,就有不同的結果:
a = ["eyelash","test"] #定義一個陣列
c = ["eyelash","test"] #定義相同內容的陣列
print(a == c) # 結果會是True
print(a is c) # 結果會是False
結果會是不同的,到底為何會這樣?
原來「==
」是比較運算子(Comparison operators),像是>
、<
、!=
等等,都是相同的一類;而「is
」是身分運算子(Identity operators),他則是與is not
一組。
他們差別就是在不同的運算子中,比較運算子是比對兩者的值是否相同,就好像1+1
是否等於2
,這樣的值比較。但是身分運算子就不同,他是做身分的比較,也就是比對是否為相同的物件,是否在記憶體相同的位置,也就是使用id()
(詳細說明參考:文件)看看是否相同。
像第一個範例,都是字串eyelash
,他們的記憶體位置為(使用id("eyelash")
):4439806512
,因此無論是值都是「eyelash」,而記憶體位置也是相同的,所以兩個運算子結果都是True
。
第二的範例中,改成陣列。內容相同,因此在比較運算子==
的判斷,也會相同;但是在身分運算子is
下,他們是不同的記憶體位置,所以就是不同的結果。這會在記憶體參考的物件,像是陣列[]或是字典dict
等等有不同的效果,在使用上不得不注意。
同場加映:
無意間發現有趣現象:
a = ["eyelash","test"] # 與第二個範例相同
c = ["eyelash","test"] # 與第二個範例相同
print(f"a[0] is c[0] => [{a is c}]") # 結果是: a[0] is c[0] => [False]
print(f"a[0] is c[0] => [{a[0] is c[0]}]") # 結果是: a[0] is c[0] => [True]
明明上面說,使用陣列[]
是不同的記憶體位置,第一個print
顯示也是False
,但為什麼在取裡面的值時,卻比對是True
,連a[1] is c[1]
也是True
,不就全部都是True
了嗎?
為了驗證是否如我想,使用id()
的方式查,發現原來相同文字的值都是相同位置,但是陣列主體卻是不同的:
id(a) # 結果是:4438986416
id(c) # 結果是:4439810448
a is c # 結果是:False
id(a[0]) # 結果是:4439806512
id(c[0]) # 結果是:4439806512
a[0] is c[0] # 結果是:True
id("eyelash") # 結果是:4439806512
a[0] is "eyelash" # 結果是:True
c[0] is "eyelash" # 結果是:True
陣列他們兩個主體不同,記憶體位置不同,由於他們的值都是「eyelash
」,為了節省空間,所以相同的值都導向相同記憶體,因此才會a is c
為False
,但是a[0]
卻和c[0]
卻相同。
參考資料:
- Python文件:comparison
- Python文件:value comparison
- Python文件:identity comparison
- Python文件:id()
- 運算子
- Python operator
~Copyright by Eyelash500~
IT技術文章:EY*研究院
iT邦幫忙:eyelash*睫毛
Blog:睫毛*Relax
Facebook:睫毛*Relax