用三个单词代替符号
Python 的逻辑运算符是英文单词 and、or 和 not。其他语言写作 &&、|| 和 !。在 Python 中 && 和 || 会引发 SyntaxError,而 ! 只出现在 !=(“不等于”)里。
对 True 和 False 来说,规则和你预期的一样:
a | b | a and b | a or b | not a |
|---|---|---|---|---|
True | True | True | True | False |
True | False | False | True | False |
False | True | False | True | True |
False | False | False | False | True |
and 要求两边都为真。or 至少需要一边为真。not 只接收一个值,并把它取反。
在实际代码中,两边通常是比较表达式,结果交给 if 或 while 使用:
输出:
eligible
standard ticket
对大多数条件来说,这些就够用了。本页其余部分介绍这些运算符遇到不是 True 或 False 的值时会做什么,以及决定表达式哪一边会执行的规则。
真值与假值
and、or 和 not 可以接收任何值,而不只是布尔值。Python 根据值的真值性来判断它算不算真。以下这些值是假值:
False和None- 任何数字类型的零:
0、0.0 - 空容器和空字符串:
""、[]、()、{}、set()、range(0)
其他一切都是真值,包括 "0"、"False"、[0] 和 -1。你可以用 bool() 查看 Python 如何判断一个值:
输出:
0 False
1 True
-1 True
'' False
'0' True
[] False
[0] True
None False
0.0 False
字符串 "0" 是真值,因为它是非空字符串。从输入读取数字、在转换之前就做判断的人常会在这里踩坑。数字与布尔值页面介绍了 bool 与 int 的关系。
and 和 or 返回的是操作数
这正是 Python 与大多数语言不同的地方。and 和 or 不会产生新的 True 或 False,而是返回你给它们的两个值之一:
- 如果
x是真值,x or y返回x,否则返回y。 - 如果
x是假值,x and y返回x,否则返回y。
当两个操作数都是布尔值时,“返回操作数”和“返回布尔值”是一回事,所以直到你混入其他类型,才会注意到这个区别。
not 是例外:它总是返回 True 或 False。
如果你需要从 and/or 表达式得到真正的布尔值,比如要存起来,或者要从一个承诺返回 bool 的函数中返回,就用 bool() 包起来:
短路求值
Python 从左到右求值 and 和 or,一旦能确定结果就停下:
and在遇到第一个假值时停下,因为后面的任何东西都不可能让整个表达式为真。or在遇到第一个真值时停下,因为后面的任何东西都不可能让整个表达式为假。
被跳过的那一边根本不会执行。用调用时会打印信息的函数,就能亲眼看到这一点:
输出:
and:
checking A
False
or:
checking A
True
两种情况下 B 都没有被检查。短路求值让守卫条件变得安全。下面每个条件的后半部分单独执行都会崩溃,但它只会在前半部分排除了危险情况之后才执行:
把开销小或起保护作用的判断放在前面。如果把顺序反过来写成 user.startswith("admin") and user is not None,当 user 是 None 时就会抛出 AttributeError。
基于 or 和 and 的写法
因为 or 返回第一个真值操作数,所以可以用一行代码设置默认值:
输出:
Hello, Ada!
Hello, guest!
Hello, guest!
问题在于,or 会替换所有假值,而不只是 None。如果 0、"" 或 [] 是合法的输入,or 会把它丢掉:
当零或空值是有效值时,请使用 x if x is not None else default。if/else 页面介绍了这种条件表达式。
and 也有对应的写法:“只有第一个值存在时才使用这个值”。这种写法不太常见,而且通常写成 if 更清楚,所以要少用:
优先级:先 not,再 and,最后 or
当一个表达式混用这三个运算符时,Python 先运算 not,然后是 and,最后是 or。==、< 和 in 这类比较运算符会在它们之前运算。
同样的值,a or b and c 和 (a or b) and c 给出的结果不同,所以即使默认顺序刚好正确,混合条件也应该加上括号。括号没有任何代价,还能让下一位读代码的人不必琢磨。
and/or 与 &/|
& 和 | 看起来像 and 和 or,有时结果也相同,但它们是不同的运算符。
and/or判断真值、会短路,并返回其中一个操作数。&/|是按位运算符。用在整数上时,它们按位组合两个数。用在集合上时,表示交集和并集。用在True和False上时,返回布尔值。它们从不短路:两边总会被求值。
按位运算符的优先级也比比较运算符高,这会让用 & 写的条件变成完全不同的东西:
1 & y 就是 1 & 5,结果是 1,所以中间那行变成了链式比较 5 > 1 > 1,而 1 > 1 为假。在普通 Python 代码中,条件请使用 and、or 和 not。
唯一应该用 &、| 和 ~ 写条件的地方是 NumPy 和 pandas。数组包含许多值,没有单一的真值,所以 and 会抛出 ValueError: The truth value of an array ... is ambiguous。这些库重载了 & 和 |,让它们逐元素运算,所以 pandas 的筛选写作 df[(df.age > 18) & (df.country == "CA")],每个比较都要加括号,原因就是上面说的优先级。
any() 和 all():对整个列表做 and 和 or
要组合一整组条件,请使用内置函数 all()(对每个元素做 and)和 any()(对每个元素做 or)。它们也会以同样的方式短路:
与 and 和 or 不同,any() 和 all() 总是返回布尔值。
常见错误
用 or 把一个变量和多个值比较。下面这个条件永远为真:
Python 把第一个条件读作 (color == "red") or "blue"。比较结果是 False,所以 or 返回 "blue",这是一个非空字符串,也就是真值。请在两边都写出完整的比较,或者更好的做法是用 in 判断成员关系。
写成 && 或 ||。两者都会引发 SyntaxError。请使用 and 和 or。
以为 and/or 会返回布尔值。x = a or b 存的是 a 或 b 本身。这通常正是你想要的,但如果函数应该返回 True 或 False,就用 bool() 转换。
在混合条件中依赖优先级。a or b and c 是合法的,含义也明确,但还是加上括号吧,这样谁都不用去记规则。
常见问题
Python 中 and 运算符有什么作用?
只有两边都为真时,a and b 才为真。Python 先求值 a;如果 a 是假值,就直接返回 a,不再看 b,否则返回 b。用在普通布尔值上时,结果和你预期的一样:True and False 是 False。
为什么 0 or 5 返回的是 5 而不是 True?
or 和 and 返回的是其中一个操作数,而不是一个新的布尔值。如果 x 是真值,x or y 返回 x,否则返回 y。0 是假值,所以 0 or 5 返回 5。如果你需要真正的 True 或 False,就用 bool() 把表达式包起来。
Python 中 and 和 & 有什么区别?
and 是逻辑运算符:它判断真值并且会短路。& 是按位运算符:用在整数上时按位组合(6 & 3 是 2),用在集合上时取交集,而且两边总会被求值。if 条件里请用 and。例外是 NumPy 和 pandas,在那里 & 表示逐元素的“与”。
Python 中 and 和 or 谁先运算?
not 优先级最高,然后是 and,最后是 or。所以 a or b and c 表示 a or (b and c),not a or b 表示 (not a) or b。==、< 这类比较运算符的优先级比这三个都高。
Python 中可以用 && 和 || 吗?
不可以。在 Python 中 && 和 || 会引发 SyntaxError。逻辑运算符是单词 and、or 和 not。单个 & 或 | 是合法的,但含义不同(按位与、按位或)。