不可思議,Python 的鏈式操作竟然可以這樣
學習 Python 的過程中,有沒有讓你出乎意料的情景,在細品之后,又覺得情理之中呢?(有的話文末留言哈)我就遇到過,初見時不可思議,仔細學習之后,又覺得豁然開朗,Python 的鏈式操作就是這樣的場景。
不可思議
比如說,你看到 True is False 的結果是 False, False is False 的結果是 True ,不會覺得有什么問題:
- >>> True is False
- False
- >>> False is False
- True
然后,當你你看到 True is False is False 的結果是 False,可能就覺得不可思議。
- >>> True is False is False
- False
- >>>
因為無論是從前計算,還是從后計算,結果都應該是 True 啊:
- >>> (True is False) is False
- True
- >>> True is (False is False)
- True
- >>>
豁然開朗
當認知和實際情況不一致的時候,恰恰是我們需要學修正自己的時候。這種操作屬于鏈式操作,Python 的官方文檔有解釋:https://docs.python.org/3/reference/expressions.html#comparisons
翻譯一下,大致意思就是 Python 中的比較運算與 C 語言不同,這些比較操作具有相同的優先級,該優先級低于任何算術,移位或按位運算。
這些比較操作包括 in, not in, is, is not, <, <=, >, >=, !=, == 操作符,會產生 True 或 False 的結果,這些比較操作符號可以任意的鏈式比較,比如:x < y <= z,x < y 與 y <= z 具有相同的優先級,不存在先計算 x < y ,得到結果后再與<=z 進行比較的情況,因此x < y <= z 與 x < y and y <= z是等價的。
x < y and y <= z 中,如果 x < y 的結果是 False,那么 y <= z 根本不會被計算。
也就是說a op1 b op2 c ... y opN z 等價于 a op1 b and b op2 c and ... y opN z,每一個表達式最多被執行一次。
注意,a op1 b op2 c 并不代表 a 和 c 有必然的關系,比如這樣寫x < y > z 也是合法的,雖然并不好看。
那么開始的問題就變得簡單了:
- True is False is False
相當于
- (True is False) and (False is False)
結果自然就是 False。
相信,現在你已經明白了下面的現象:
- >>> 1 in [0,1] == True
- False
- >>> not True in [True,False]
- False
然后,我再分享一下鏈式操應用的好例子和壞例子。
好例子,一目了然:
- if 0 < x < 1:
- print("x in range (0,1)")
- if 0 <= x < 1:
- print("x in range [0,1)")
- if x <= y <= z:
- print("y in range [x,z]")
- if x >= y >= 1:
- print("y in range [1,x]")
- if x == y == z:
- print("x,y,z all equal")
壞例子,不知所云。我們應該避免這樣寫:
- if x < y > z:
- print("y > max(x,z)")
- if x != y != z:
- print("kinda looks like x,y,z all distinct, but may have x==z")
- if 0 > x < y != z > 1:
- print("WHY??")
- if 0 < x > 1 >> y << 1 < z > 1:
- print("please remove this from the language")
用法沒問題,但可能讓人產生疑問的,類似文章開頭的例子,也盡量避免:
- if 0 < x < y == z < 1:
- print("x,y in (0,1) with x<y and z==y")
- if x <= y <= z != 1:
- print("y in range(x,z) with z != 1")
- if x == y == z != 1:
- print("x,y,z all equal something that isn't 1")
- if x is y is z:
- print("x,y,z all identical")
- if x is y is z in [1, 2, 3]:
- print("x,y,z all identical and in [1,2,3]")