在赋值右侧使用'or'符合Python风格吗?

9 投票
2 回答
540 浏览
提问于 2025-04-18 04:58

情况

(注意:以下情况只是个例子。这个问题适用于任何可以判断真假(bool)的情况)

如果用户没有提供自定义列表,就应该使用默认列表:

default_list = ...
custom_list = ...
if custom_list:
    list = custom_list
else:
    list = default_list

你可以把它简化为:

default_list = ...
custom_list = ...
list = custom_list if custom_list else default_list

根据 这个链接 ...

表达式 x or y 首先会判断 x;如果 x 为真,它就返回 x 的值;否则,就会判断 y,并返回 y 的值。

... or 并不是返回一个真假值,而是返回第一个不是假的值。因此,下面的代码是有效的:

list = custom_list or default_list

这和 C# 的空合并运算符有点像,但在 Python 中应该称为 假合并运算符,它返回第一个 非假 的参数。

问题

最后一个例子似乎更容易阅读,但这算不算是 Python 风格呢?

无论是 pep8(一个代码风格检查工具)还是 pylint(另一个检查工具)都没有提出问题。

2 个回答

5

是的,以前大家常常用 or 来利用它的短路特性,这在语言中添加条件表达式之前是很普遍的做法。

用下面的方式是完全符合 Python 风格的:

foo = bar or baz

这样可以在 bar 为假(在布尔上下文中计算为假)时,使用一个默认值。因为它有短路特性,所以你还可以做到:

foo = bar or expensive_calculation(baz)  # only if bar is false-y

这样就不会在 bar 为真(在布尔上下文中计算为真)时执行 expensive_calculation()。同样,你也可以用 and 来确保某些前提条件被满足:

foo = bar and bar(baz)  # call `bar()` only if it is truth-y

不过,对于以下情况,你 应该 使用条件表达式:

foo = bar and spam or eggs

这是条件表达式的目的所在。它的想法是,如果 bar 为真,就选择 spam,否则选择 eggs。但如果 spam 为假,这个逻辑就会出问题!这常常是错误的来源,而

foo = spam if bar else eggs

bar 为真时,总是选择 spam

5

这完全是有效的,你可以这样使用。甚至连关于or的文档里也有类似的例子。

需要注意的是,andor并不限制返回的值和类型为FalseTrue,而是返回最后一个被计算的参数。这有时候很有用,比如,如果s是一个字符串,当它为空时应该用默认值替代,那么表达式s or 'foo'就能得到你想要的值。

不过,or方法有一个局限性。如果你想故意允许一个非真值,那么用这个方法是可能的。

假设你想允许一个空列表

my_list = [] or default_list

这总是会返回default_list。比如,

print [] or [1, 2, 3]
# [1, 2, 3]

但是使用条件表达式我们可以这样处理

custom_list if isinstance(custom_list, list) else default_list

翻看一下旧文档,引用一下BDFL的常见问题解答

4.16. 问:有没有类似C语言的“?:”三元运算符?

答:没有直接的等价物。在很多情况下,你可以用a and b or c来模拟a?b:c,但有一个缺陷:如果b是零(或为空,或None——任何测试为假的东西),那么就会选择c。在很多情况下,你可以通过查看代码证明这种情况不会发生(例如,因为b是一个常量或有一个永远不会为假的类型),但一般来说,这可能会成为一个问题。

Steve Majewski(还是Tim Peters?)建议了以下解决方案:(a and [b] or [c])[0]。因为[b]是一个单元素列表,它永远不会为假,所以不会走错路径;然后对整个表达式应用[0]就能得到你真正想要的bc。虽然看起来不太优雅,但在某些情况下,确实不方便用'if'重写代码时,这个方法能帮你解决问题。

撰写回答