基本概念:短路求值

  • andor 在 Python 中按照 从左到右 的顺序求值。

  • 短路规则

    • A and B:先求 A,如果 A假值(falsy),直接返回 A(不计算 B);否则返回 B 的值(会计算 B)。
    • A or B:先求 A,如果 A真值(truthy),直接返回 A(不计算 B);否则返回 B 的值(会计算 B)。

注意and/or 不一定返回 True/False,而是返回其中一个操作数(第一个决定结果的操作数或最后一个操作数)。

真值 / 假值(truthy / falsy)

在布尔上下文中,以下常被视为假值(falsy):

  • False, None
  • 数值 0, 0.0, 0j
  • 空序列/集合:'', (), [], {}, set()
  • 自定义对象如果实现 __bool__() 返回 False__len__() 返回 0

其它一般都是真值(truthy)

返回值规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# or 示例
>>> "a" or "b"
'a' # "a" 真值,返回第一个真值
>>> "" or "b"
'b' # "" 假值,返回第二个值 "b"

# and 示例
>>> "a" and "b"
'b' # "a" 真值,返回第二个值 "b"
>>> "" and "b"
'' # "" 假值,返回第一个假值

# 组合
>>> None or 0 or "" or "ok" or "last"
'ok' # 第一个真值
>>> 0 and 1 and 2
0 # 第一个假值

常见用法

默认值 / 回退

常见写法:

1
name = provided_name or "匿名用户"

含义:若 provided_name 为假(None / '' / 0 等),使用 "匿名用户"
注意:当你只想在 None 时使用默认值,而允许空字符串或 0 时保留原值,应改用 if x is None: x = default 或三元表达式 x if x is not None else default

连续回退

1
value = a or b or c or d

等价于“选出第一个 truthy 值”,常用于 config 合并、参数回退等。

条件执行的快速写法(不推荐)

利用 and 的短路做“条件执行”:

1
condition and do_something()

如果 condition 为真则执行 do_something(),否则不调用。
注意:这种用法依赖副作用(函数调用),可读性较差,通常建议用显式 if

1
2
if condition:
do_something()

旧式三元 / 选择表达式替代(容易出错)

以前有时会见到:

1
res = cond and value_if_true or value_if_false

并不总是等价value_if_true if cond else value_if_false,当 value_if_true 为假值时会返回 value_if_false(即误判)。
正确且可读的写法(Python 2.5+):

1
res = value_if_true if cond else value_if_false

与函数调用的短路

1
result = expensive() or fallback()

如果 expensive() 返回真值则不会调用 fallback()(短路)。这在控制副作用或性能时有用。

短路与强制布尔化

如果你只关心真/假,把表达式包装 bool()

1
flag = bool(a and b)   # 强制得到 True/False

优先级与求值顺序

  • not 的优先级高于 andand 高于 or
  • 比较运算(如 <, >, ==)的优先级高于 and/or(即 a < b and b < c 的语义是 (a < b) and (b < c));
  • 所有操作按左到右求值;有短路时右侧可能根本不被求值。

示例优先级:

1
2
>>> True or False and False
True # 等价于 True or (False and False)

若优先级会让人混淆,请加括号以明确意图:

1
res = (a and b) or c

注意事项

  1. or 当作“只检查 None”会出错

    1
    2
    x = 0
    y = x or 100 # y == 100,但你可能想保留 0

    如果只想在 None 时回退:

    1
    y = x if x is not None else 100

    或:

    1
    y = 100 if x is None else x
  2. and/or 返回操作数,不是布尔值
    在逻辑判断你想得到 True/False,请用 bool(expr)if expr:。不要依赖 and/or 返回类型恰好是布尔值。

  3. and/or 做三元表达式的旧写法可能有 bug

  4. 副作用与短路
    如果右侧表达式有副作用(修改全局、写文件、网络请求等),短路会影响是否执行这些副作用。要小心使用,必要时写成显式 if

  5. 对象自定义真值
    自定义对象的 __bool____len__ 会影响短路结果。设计类时注意这些方法的语义。

  6. 链式赋值陷阱
    表达式 a = b or c 只是在 a 中放入结果,并不会改变 bc。如果想修改原变量,需要显式赋值。

示例与对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 示例 1:or 作为默认值
>>> name = ""
>>> display = name or "Guest"
>>> display
'Guest' # 空字符串被视为假值

# 示例 2:and 作为条件执行
>>> def side_effect():
... print("called")
... return True
...
>>> False and side_effect()
# Nothing printed, side_effect() 未被调用

>>> True and side_effect()
called
True

# 示例 3:a and b or c 的坑
>>> cond = True
>>> value_if_true = 0 # 假值
>>> value_if_false = 5
>>> res = cond and value_if_true or value_if_false
>>> res
5 # 期望 0,但得到 5 —— 因 value_if_true 是假
# 正确写法:
>>> res = value_if_true if cond else value_if_false
>>> res
0

总结

  • and/or 左到右求值并短路,返回操作数之一,而非总是布尔值。
  • or 常用于回退(但要注意假值会触发回退)。
  • and 常用于“如果左真则执行右边/返回右边”,但副作用写法可读性差。
  • 遇到复杂逻辑优先用显式 if / 三元表达式,避免难以维护的技巧写法。
  • 理解假值规则、优先级与短路顺序是避免陷阱的关键。