(四)判断、真假值与短路求值
1. 比较与真假值
# 比较表达式得到 True 或 False。
minutes = 45
print(minutes >= 30)
print(minutes == 30)
print(minutes != 30)
# 链式比较把同一个值与上下两端比较。
print(0 <= minutes <= 120)== 比较内容是否相等,!= 判断不相等。a < b < c 相当于依次检查相邻两段比较,位于中间的表达式只求值一次。
对象也可以被放到需要判断真假的位置。bool(...) 显示它在这种位置对应的真假值:
# 零、空字符串和 None 在真假判断中为假。
print(bool(0), bool(""), bool(None))
# 非零数和非空字符串为真;文本 "False" 也不是空字符串。
print(bool(-1), bool("0"), bool("False"))输出 False False False 和 True True True。bool("False") 不会把文本翻译成布尔字面量。后面会看到,空列表、空字典和空集合在判断中同样为假。
2. and、or 与实际求值顺序
假设要先检查目标是否设置,再检查阅读时间是否达到目标:
# 左边为假时,and 已经能确定整体结果,不再计算右边。
target = None
minutes = 45
print(target is not None and minutes >= target)
# 左边已提供一个真值时,or 直接返回左边的值。
nickname = ""
print(nickname or "未填写昵称")第二个例子输出 未填写昵称。and、or 会返回参与判断的操作数,不一定返回布尔对象:
# and 返回左侧假值或最后需要求值的操作数。
print(0 and 99)
print(5 and 99)
# or 返回左侧真值或最后需要求值的操作数。
print("已填写" or "默认值")
print("" or "默认值")输出 0、99、已填写、默认值。not 则把真假值取反,结果是 True 或 False。
先看左边能否决定结果。图中 target 为 None,第一项为假,后面的数值比较没有执行。把 target 改成 30,才会继续比较 45 >= 30。
3. 组合表达式的优先级
同一行出现多种运算时,先确定哪些部分组合在一起,再计算它们的值。不用死记硬背优先级,实际写代码时可以直接加括号。 例如把 a + b * c 写成 a + (b * c),就明确表示先算乘法;需要先加后乘时,写成 (a + b) * c。括号也让读代码的人更容易确认你的意思。
下面的表留作查阅,遇到已有代码或需要确认规则时再回来看。常用层次从高到低排列:
| 从高到低的层次 | 主要写法 | 阅读动作 |
|---|---|---|
| 显式分组 | (表达式) |
按括号明确组合 |
| 幂 | ** |
从右侧组合连续的幂 |
| 一元运算 | +x、-x、~x |
作用到后面的一个值 |
| 乘除与余数 | *、/、//、% |
同层通常从左到右组合 |
| 加减 | +、- |
再处理相加与相减 |
| 移位 | <<、>> |
对整数移动二进制位 |
| 按位与 | & |
逐位合并 |
| 按位异或 | ^ |
逐位比较是否不同 |
| 按位或 | | |
逐位合并 |
| 比较、身份与成员关系 | <、<=、==、!=、>=、>、is、is not、in、not in |
得到比较结果;成员关系在字符串和容器中继续使用 |
| 逻辑取反 | not |
反转真假值 |
| 逻辑与 | and |
结合短路规则读取操作数 |
| 逻辑或 | or |
最后组合这些条件 |
# 先算乘法,显式分组后则先算加法。
print(2 + 3 * 4, (2 + 3) * 4)
# and 比 or 结合得更紧;括号改变条件的组合。
print(True or False and False, (True or False) and False)
# not 读取整个比较结果,而不是先反转左边的整数。
print(not 2 == 2, not (2 == 2))输出 14 20、True False、False False。优先级确定表达式的组合,短路规则决定其中哪些部分真的执行。幂右侧也能接一元负号,例如 2 ** -1 读成 2 ** (-1),得到 0.5;前面的 -2 ** 2 则读成 -(2 ** 2)。
写较长条件时,用括号直接标出准备一起判断的部分。后面的 NumPy 示例写 (a >= 20) & (a < 40),也是先分别比较,再合并结果。运算符优先级