深入理解 Python and 邏輯運算符(踩坑)

1. 引子

def enabled() -> bool:
    a = ["a,"b"]
	b = True
    c = False
    return (b and c) or (b and a)

以上代碼返回什麼?

實際生產項目踩到的坑,也怪自己沒理解到未,才疏學淺!!!

想當然的以爲 python 自己會做真值判斷了。其實真值判斷是在 if 條件語句時會生效,但在普通的 and 的運算符下有另外一個規則。

2. python bool 類型簡述

“The Boolean type is a subtype of the integer type, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings ‘False’ or ‘True’ are returned, respectively.”

“布爾類型是整數類型的一個子類型,在幾乎所有的上下文環境中布爾值的行爲類似於值0和1,例外的是當轉換爲字符串時,會分別將字符串”False“或”True“返回。“

就python而言,True,1和1.0都表示相同的字典鍵

>>> True == 1 == 1.0
True
>>> (hash(True), hash(1), hash(1.0))
(1, 1, 1)

>>> issubclass(bool, int)
True
>>> isinstance(True, int)
True
>>> isinstance(False, int)
True
>>> int(True)
1
>>> int(False)
0

>>> help(bool)

Help on class bool in module builtins:

class bool(int)
    |  bool(x) -> bool
    |
    |  Returns True when the argument x is true, False otherwise.
        |  The builtins True and False are the only two instances of the class bool.
        |  The class bool is a subclass of the class int, and cannot be subclassed.

3. bool類型之間的 and 運算

and 運算符有兩個操作數,可以是 bool,object,或一個組合

>>> True and True
True

>>> False and False
False

>>> True and False
False

>>> False and True
False

以上示例表明,僅當表達式中的兩個操作數都爲 true 時,和表達式才返回 True。由於 and 運算符需要兩個操作數來構建表達式,因此它是一個二元運算符。

當兩邊操作書都爲 bool 類型時,二元操作運算結果如下。

operand1 operand2 operand1 and operand2
True True True
True False False
False False False
False True False

當然,以上的結果也適用於兩邊操作數一個 bool 表達式的情況。

expression1 and expression2

>>> 5>3 and 5==3+2
True

4. 不同類型之間的 and 運算

可以使用 and 運算符在單個表達式中組合兩個 Python 對象。在這種情況下,Python 使用內部的bool() 來判斷操作數的真值。此時,兩個對象之間的運算,結果將獲得一個特定的對象,而不是布爾值。僅當給定操作數顯式計算爲 True 或 False 時,纔會獲得 True 或 False

>>> 2 and 3
3
>>> 5 and 0.0
0.0
>>> [] and 3
[]
>>> 0 and {}
0
>>> 1 and {}
{}
>>> False and ""
False
>>> True and ""
''
>>> ["a"] and [1]
[1]

根據以上測試用例結果,當and運算結果爲 False 時返回左操作數,當and運算結果爲 True 時返回右操作數

關於真值的判斷規則,在 python 的文檔中有說明

Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below.

By default, an object is considered true unless its class defines either a bool() method that returns False or a len() method that returns zero, when called with the object. 1 Here are most of the built-in objects considered false:

  • constants defined to be false: None and False
  • zero of any numeric type: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • empty sequences and collections: '', (), [], {}, set(), range(0)

https://docs.python.org/3/library/stdtypes.html#truth-value-testing

以下是對象之間的比較結果集

object1 object2 object1 and object2
False False object1
False True object1
True True object2
True False object2

綜上:如果 and 表達式中的操作數是對象而不是布爾表達式,則運算符在計算結果爲 False 時返回左側的對象。否則,它將返回右側的對象,即使其計算最終結果爲 False。

⚠️:如果在做對象邏輯運算,最終結果想得到 bool 類型 True/False的話,可以使用內建函數 bool(expression) 將結果重新實例化一下在返回

5. 高效運算-“快速短路”(short-circuit operator)

短路操作器,聽這個名字就知道是快速運算,Python 的邏輯運算符,如 and and or,使用稱爲短路求值或惰性求值的東西來加速運算,高效得到結果。

例子:爲了確認 and 表達式的最終結果,首先計算左操作數,如果它是False,那麼整個表達式都是False。在這種情況下,無需計算右側的操作數,就已經知道最終結果了

>>> def true_func():
...     print("Running true_func()")
...     return True
...

>>> def false_func():
...     print("Running false_func()")
...     return False
...

>>> true_func() and false_func()  # Case 1
Running true_func()
Running false_func()
False

>>> false_func() and true_func()  # Case 2
Running false_func()
False

>>> false_func() and false_func()  # Case 3
Running false_func()
False

>>> true_func() and true_func()  # Case 4
Running true_func()
Running true_func()
True

短路操作器,是提升代碼性能的一種有效手段。在邏輯運算表達式時,可考慮如下兩個原則:

  1. 將耗時的表達式放在 and 關鍵字的右側。這樣,如果短路規則生效,則不會運行代價高昂的表達式。
  2. 將更有可能爲 false 的表達式放在 and 關鍵字的左側。這樣, 更有可能通過僅計算左操作數來確定整個表達式是否爲 false。

當然,如果一定要執行運算符兩邊的表達式,則可以使用位運算符號 (&, |, ~),替代邏輯運算符

>>> def true_func():
...     print("Running true_func()")
...     return True
...

>>> def false_func():
...     print("Running false_func()")
...     return False
...

>>> # Use logical and
>>> false_func() and true_func()
Running false_func()
False

>>> # Use bitwise and
>>> false_func() & true_func()
Running false_func()
Running true_func()
False

6. bool 邏輯運算的萬能公式

Operation Result Notes
法則 1 x or y if x is true, then x, else y 1
法則 2 x and y if x is false, then x, else y 2
法則 3 not x if x is false, then True, else False 3

Notes:

  1. This is a short-circuit operator, so it only evaluates the second argument if the first one is false.
  2. This is a short-circuit operator, so it only evaluates the second argument if the first one is true.
  3. not has a lower priority than non-Boolean operators, so not a == b is interpreted as not (a == b), and a == not b is a syntax error.

多複雜的組合表達式,最終都可以一重重拆解成一個個獨立的小單元,在做合併

就拿開頭的引子來說

def enabled() -> bool:
    a = ["a,"b"]
	b = True
    c = False
    return (b and c) or (b and a)

拆成三步來看

  1. b and c --> 運用法則 2 (if x is false, then x, else y) 所以結果是 c 即 False
  2. b and a --> a 運用法則 2 (if x is false, then x, else y) 所以結果是 a 即 ["a", "b"]
  3. False or ["a", "b"] 運用法則 1 (if x is true, then x, else y) 所以結果是 ["a", "b"]

7. 參考

  1. python-and-operator
  2. python-docs-truth-value-testing
  3. Python3 源碼閱讀 數據類型-Int.md
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章