Python 支援以下基本的比較運算子:
| 運算子 | 運算 | 說明 |
|---|---|---|
> |
「大於」 | 若 a 的值嚴格大於 b,則 a > b 為 True
|
< |
「小於」 | 若 a 的值嚴格小於 b,則 a < b 為 True
|
== |
「等於」 | 若 a 的值嚴格等於 b,則 a == b 為 True
|
>= |
「大於或等於」 | 若 a > b 或 a == b,則 a >= b 為 True
|
<= |
「小於或等於」 | 若 a < b 或 a == b,則 a <= b 為 True
|
!= |
「不等於」 | 若 a == b 為 False,則 a != b 為 True
|
is |
「同一性」 | 若 a 和 b 是同一_物件_,則 a is b 為 True(且僅限於此情況) |
is not |
「否定的同一性」 | 若 a 和 b 不是同一_物件_,則 a is not b 為 True
|
in |
「包含測試」 | 若 a 是 b 的成員、子集合或元素,則 a in b 為 True
|
not in |
「否定的包含測試」 | 若 a 不是 b 的成員、子集合或元素,則 a not in b 為 True
|
它們的優先順序都相同(高於 布林運算,但低於算術或位元運算)。
不同型態的物件(數值型態除外)預設永遠不會比較為相等。
class 的非同一實例也 不會 比較為相等,除非該 class 定義了特殊的 豐富比較 方法,來自訂 object 預設的比較行為。
透過 rich comparisons 進行自訂會在某個後續的練習中介紹。
關於這個主題的(更多)細節,請參閱 Python 文件中的 值比較。
數值型態(大多)是這個型態配對規則的例外。
只要型態可以隱含轉換以供比較,integer 可以被視為等於 float(或 octal 等於 hexadecimal)。
對於 Python 標準函式庫中的其他數值型態(複數、十進位數、分數),比較運算子只在「合理」的地方才有定義(隱含轉換不會改變結果的地方),但如果底層物件無法準確轉換以供比較,就會擲出 TypeError。
關於 Python 用於_數值轉換_的規則的詳細資訊,請參閱 Python 文件中的 算術轉換。
>>> import fractions
# A string cannot be converted to an int.
>>> 17 == '17'
False
# An int can be converted to float for comparison.
>>> 17 == 17.0
True
# The fraction 6/3 can be converted to the int 2
# The int 2 can be converted to 0b10 in binary.
>>> 6/3 == 0b10
True
# An int can be converted to a complex number with a 0 imaginary part.
>>> 17 == complex(17)
True
# The fraction 2/5 can be converted to the float 0.4
>>> 0.4 == 2/5
True
>>> complex(2/5, 1/2) == complex(0.4, 0.5)
True
任何數字與 NaN(不是數字)型態進行的有序比較結果都是 False。
Python NaN 定義的一個令人困惑的副作用是:NaN 永遠不會等於 NaN。
>>> x = float('NaN')
>>> 3 < x
False
>>> x < 3
False
# NaN never compares equal to NaN
>>> x == x
False
與數字不同,字串(str)是使用各自的 Unicode 碼點依字典序進行比較(也就是將 str 中的每個碼點傳入內建函式 ord() 所得到的結果,它會回傳一個 int)。
如果兩個字串中的所有碼點都相符,且 順序相同,這兩個字串就被視為相等。
這種比較是以「成對」的方式進行:第一個對第一個、第二個對第二個,依此類推。
在 Python 3.x 中,str 和 bytes 無法直接強制轉換或比較。
>>> 'Python' > 'Rust'
False
>>> 'Python' > 'JavaScript'
True
# Examples with Mandarin.
# hello < goodbye
>>> '你好' < '再见'
True
# ord() of first characters
>>> ord('你'), ord('再')
(20320, 20877)
# ord() of second characters
>>> ord('好'), ord('见')
(22909, 35265)
# And with Korean words.
# Pretty < beautiful.
>>> '예쁜' < '아름다운'
False
>>> ord('예'), ord('아')
(50696, 50500)
比較運算子可以_任意_串接,意思是它們能以任何長度的任何組合來使用。
請注意,運算式的求值是由 left 到 right 進行。
舉例來說,x < y <= z 等於 x < y and y <= z,差別在於 y 只會被求值一次。
在兩種情況下,當發現 x < y 為 False 時,z 完全_不會_被求值。
這通常稱為 short-circuit evaluation:如果運算式的真值已經確定,求值就會停止。
Short circuiting 受到各種布林運算子、函式的支援,Python 中的比較串接也支援它。
與許多其他程式語言(包括 C、C++、C# 和 Java)不同,Python 中像 a < b < c 這樣的串接運算式具有傳統的數學詮釋與優先順序。
>>> x = 2
>>> y = 5
>>> z = 10
>>> x < y < z
True
>>> x < y > z
False
>>> x > y < z
False
運算子 is 和 is not 測試的是物件的同一性,而非物件的_值_。
物件建立之後,其同一性永遠不會改變,可以透過 id() 函式取得。
若 且僅限於 id(<apple>) == id(<orange>),則 <apple> is <orange> 的求值結果為 True。
<apple> is not <orange> 則會得到相反的結果。
由於 None 和 NotImplemented 具有單例的地位,應該一律使用 is 和 is not 來與項目進行比較。
關於這個慣例的更多細節,請參閱 Python 參考文件中的值比較和 PEP8。
>>> my_fav_numbers = [1, 2, 3]
>>> your_fav_numbers = my_fav_numbers
>>> my_fav_numbers is your_fav_numbers
True
# The returned id will differ by system and python version.
>>> id(my_fav_numbers)
4517478208
# your_fav_numbers is only an alias pointing to the original my_fav_numbers object.
# Assigning a new name does not create a new object.
>>> id(your_fav_numbers)
4517478208
>>> my_fav_numbers is not your_fav_numbers
False
>>> my_fav_numbers is not None
True
>>> my_fav_numbers is NotImplemented
False
運算子 in 和 not in 測試的是_成員資格_。
若 <fish> 是 <soup> 的成員(<fish> 是 <soup> 的子集合,或包含於 <soup> 之中),則 <fish> in <soup> 的求值結果為 True,否則為 False。
<fish> not in <soup> 會回傳其否定,也就是 <fish> in <soup> 的_相反結果_。
對於字串和位元組型態,若 且僅限於 <name> 是 <fullname> 的子字串,則 <name> in <fullname> 為 True。
# A set of lucky numbers.
>>> lucky_numbers = {11, 22, 33}
>>> 22 in lucky_numbers
True
>>> 44 in lucky_numbers
False
# A dictionary of employee information.
>>> employee = {'name': 'John Doe',
'id': 67826, 'age': 33,
'title': 'ceo'}
# Checking for the membership of certain keys.
>>> 'age' in employee
True
>>> 33 in employee
False
>>> 'lastname' not in employee
True
# Checking for substring membership
>>> name = 'Super Batman'
>>> 'Bat' in name
True
>>> 'Batwoman' in name
False
在這個練習中,你將會實作二十一點的某些規則,例如遊戲的進行方式與計分方式。
注意:在這個練習中,_A代表么點,J代表傑克,Q代表皇后,而K_代表國王。
鬼牌會被移除。
這裡假設使用的是一副標準的法式 52 張撲克牌,但在大多數玩法中,會將數副牌一起洗勻後再玩。
在二十一點中,么點究竟值 1 分還是 11 分,由每位玩家自行決定(之後會再詳細說明)。
人頭牌(J、Q、K)計為 10 分,其餘的牌則依其「點數」(數值)計分。
定義value_of_card(<card>)函式,參數為card。
這個函式應該回傳傳入的牌面字串所代表的_數值_。
由於么點可以有多個值(1 或 11),這個函式目前會先把么點牌的值固定為 1。
稍後你將會實作一個函式,在已知現有手牌的情況下判斷么點牌的值。
>>> value_of_card('K')
10
>>> value_of_card('4')
4
>>> value_of_card('A')
1
定義higher_card(<card_one>, <card_two>)函式,參數為card_one和card_two。
就計分而言,J、Q或K的值為 10。
這個函式應該回傳哪張牌在計分上具有較高的值。
如果兩張牌的值相同,就回傳兩張。
只要在return敘述中使用逗號,就能回傳兩張牌:
# Using a comma in a return creates a Tuple. Tuples will be covered in a later exercise.
>>> def returning_two_values(value_one, value_two):
return value_one, value_two
>>> returning_two_values('K', '3')
('K', '3')
么點可以有多個值,所以在這個任務中,我們會把A牌的值固定為 1。
>>> higher_card('K', '10')
('K', '10')
>>> higher_card('4', '6')
'6'
>>> higher_card('K', 'A')
'K'
正如前面提到的,么點的值可能是 1 或 11 分。 玩家會盡可能讓分數接近 21,但不要_超過_ 21(也就是「爆牌」)。
定義value_of_ace(<card_one>, <card_two>)函式,參數為card_one和card_two,代表在拿到么點牌_之前_,手中已有的兩張牌。
你的函式必須判斷接下來這張么點牌的值會是 1 還是 11,並回傳該值。
記住:加上么點後的這手牌,其值要盡可能地高,但_不能_超過 21。
提示:如果手牌中已經有么點,那麼接下來這張么點的值就是 1。
>>> value_of_ace('6', 'K')
1
>>> value_of_ace('7', '3')
11
如果玩家拿到的前兩張牌是一張么點(A)和一張十點的牌(10、K、Q或J),那麼這名玩家的分數就是 21。
這就稱為二十一點手牌。
定義is_blackjack(<card_one>, <card_two>)函式,參數為card_one和card_two,代表一對牌。
判斷這兩張牌是否構成二十一點,如果是就回傳布林值True,否則回傳False。
注意:分數的_計算_可以用很多種方式完成。 但如果可以的話,我們希望你檢查手牌中(或某個特定位置)**是否**有么點與一張十點的牌,而不是把整手牌的值_加總_起來。
>>> is_blackjack('A', 'K')
True
>>> is_blackjack('10', '9')
False
如果一手牌的前兩張牌值相同(例如兩張 6,或一張Q和一張K),玩家可以選擇把它們當成兩手獨立的牌來處理。
這就稱為「拆分對子」。
定義can_split_pairs(<card_one>, <card_two>)函式,參數為card_one和card_two,代表一對牌。
判斷這手兩張牌是否可以拆分成兩手。
如果這手牌可以拆分,就回傳布林值True,否則回傳False。
>>> can_split_pairs('Q', 'K')
True
>>> can_split_pairs('10', 'A')
False
當一開始拿到的兩張牌加起來為 9、10 或 11 點時,玩家可以再下一筆與原本賭注相同的賭注。 這就稱為「加倍下注」。
定義can_double_down(<card_one>, <card_two>)函式,參數為card_one和card_two,代表一對牌。
判斷這手兩張牌是否可以「加倍下注」,可以就回傳布林值True,否則回傳False。
>>> can_double_down('A', '9')
True
>>> can_double_down('10', '2')
False