比較、指定、邏輯運算

April 12, 2022

對於大於、小於、等於這類的比較,Python 提供了 >>=<<===!= 等運算子。

比較運算

比較運算有個很 Python 的特色,就是可以串接在一起,例如 x < y <= z,其實相當於 x < y and y <= zand 是布林運算子,表示「而且」。如果願意,也可以像 w == x == y == z 這樣一直串接下去。

請注意不要將 ==!=isis not 搞混,==!= 是比較物件實際的值、狀態等的相等性,而 isis not 是比較兩個物件的參考是否相等。

想知道物件是否能進行 >>=<<===!= 等比較,以及它們比較之後的結果為何,應該看看它們的 __gt____ge____lt____le____eq____comp__ 等方法如何實作。

對於數值型態,進行 >>=<<===!= 等比較沒有問題,就是比較數字,至於其他型態,可以先知道的是,字串與 list 也能進行 >>=<<===!=,字串會逐字元依字典順序來比較,因此 'AAC' < 'ABC' 會是 True'ACC' < 'ABC' 會是 False

你可以寫一個簡單的程式,透過命令列引數指定兩個字串,看看比較的結果:

import sys

str1 = sys.argv[1]
str2 = sys.argv[2]

print(f'"{str1}" > "{str2}"  ? {str1 > str2}')
print(f'"{str1}" == "{str2}" ? {str1 == str2}')
print(f'"{str1}" < "{str2}"  ? {str1 < str2}')

一個執行結果如下:

>python compare.py Justin Monica
"Justin" > "Monica"  ? False
"Justin" == "Monica" ? False
"Justin" < "Monica"  ? True

至於 list,是逐元素進行比較,因此 [1, 2, 3] == [1, 2, 3] 結果是 True,然而 [1, 2, 3] > [1, 3, 3] 結果會是 False

指定運算

到目前為止只看過一個指定運算子,也就是 = 運算子,事實上指定運算子還有以下幾個:

指定運算子 範例 結果
+= a += b a = a + b
-= a -= b a = a - b
*= a *= b a = a * b
/= a /= b a = a / b
%= a %= b a = a % b
&= a &= b a = a & b
= a |= b a = a | b
^= a ^= b a = a ^ b
<<= a <<= b a = a << b
>>= a >>= b a = a >> b

指定運算子構成了陳述句(Statement)而不是運算式(Expression),也就是這些指定運算子不會有傳回值,因此無法作為函式呼叫時的引數,或任何需要運算式的場合,例如:

>>> print(a = 10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'a' is an invalid keyword argument for print()
>>>

從 Python 3.8 開始,新增了指定運算式(Assignment Expressions )特性,透過 := 運算子,可以完成指定,而且會將指定的值作為結果傳回,例如:

>>> print(a := 10)
10
>>>

因為 := 運算子橫著看,像個海象的臉,社群中亦稱其為海象運算子(Walrus Operator),然而對其有正反面不同的看法,有些開發者認為某些場合中它很有用,另一群開發者覺得這讓指定必須區分陳述句、運算式的不同,也可能被濫用而令程式碼變得複雜。

我的看法是,一切以可讀性為優先,如果有助於閱讀程式就使用。

邏輯運算

在邏輯上有所謂的「且」、「或」與「反相」,Python 也提供對應的邏輯運算子(Logical operator),分別為 andornot。底下這個程式是個簡單的示範,可以判斷命令列引數指定的兩個字串大小寫關係:

import sys

str1 = sys.argv[1]
str2 = sys.argv[2]

print('兩個都大寫?', str1.isupper() and str2.isupper())
print('有一個大寫?', str1.isupper() or str2.isupper())
print('都不是大寫?', not (str1.isupper() or str2.isupper()))

一個執行結果如下:

>python uppers.py Justin MONICA
兩個都大寫? False
有一個大寫? True
都不是大寫? False

NoneFalse00.00j''()[]{} 等傳給 bool,都會傳回 False,這些型態的其他值傳入 bool,都會傳回 True。在 andornot 運算時,遇到非 bool 型態時,也是這麼判斷。例如,若 valueNoneFalse00.00j''()[]{} 等其中之一,那麼 not value 結果都會是 True

andor 有捷徑運算的特性。and 左運算元若判定為假,就可以確認邏輯不成立,因此不用繼續運算右運算元;or 是左運算元判斷為真,就可以確認邏輯成立,不用再運算右運算元。當判斷確認時停留在哪個運算元,就會傳回該運算元,例如:

>> [] and 'Justin'
[]
>>> [1, 2] and 'Justin'
'Justin'
>>> [] or 'Justin'
'Justin'
>>> [1, 2] or 'Justin'
[1, 2]
>>>

分享到 LinkedIn 分享到 Facebook 分享到 Twitter