Python中的布尔运算(即:与/或运算符)

12 投票
5 回答
7055 浏览
提问于 2025-04-16 04:46

这个方法会寻找第一个由字母、数字或下划线组成的字符组(也就是 [a-zA-Z0-9_]),如果找到就返回这个组,如果没找到就返回 None

def test(str):
    m = re.search(r'(\w+)', str)
    if m:
        return m.group(1)
    return None

这个功能也可以用另一种方式来写:

def test2(str):
    m = re.search(r'(\w+)', str)
    return m and m.group(1)

这两种写法的效果是一样的,而且文档中也有说明;正如这个页面明确指出的:

表达式 x and y 首先会计算 x;如果 x 是假(也就是值为0或空),那么就返回 x 的值;如果 x 是真,接着就计算 y,并返回 y 的值。

不过,因为 and 是一个布尔运算符(手册上也提到这一点),我原本以为它会返回一个布尔值。结果我发现这个用法让我感到很惊讶

还有哪些其他的用法呢?或者说,这种看起来不太直观的实现背后有什么原因呢?

5 个回答

1

简单来说,a and b 会返回一个和整个表达式真值相同的操作数。

这听起来可能有点复杂,但你可以在脑海中想象一下:如果 aFalse,那么 b 就不重要了(因为 False and 任何东西 永远都是 False),所以它可以直接返回 a

但是当 aTrue 的时候,只有 b 才重要,所以它会直接返回 b,甚至都不需要看。

这是很多编程语言都会做的一种非常常见且基本的优化。

4

这还有什么其他的用法呢?

没有。

这个实现方式听起来不太直观,为什么会这样呢?

“不直观”?真的?我不同意。

我们来想想。

当我们说“a b”时,如果 a 是假的,那么整个表达式就是假的。所以只要找到第一个假的值,就能知道结果了。为什么还要把 a 转换成另一个布尔值呢?它已经是假的了。False 还会更假吗?其实是一样的假,对吧?

所以当 a 的值等于 False 时,它已经足够假了,这就是整个表达式的值。没有必要再进行其他转换或处理。就这样。

a 的值等于 True 时,b 的值就是我们需要的全部。也不需要再转换或处理。为什么要把 b 转换成另一个布尔值呢?它的值就是我们想知道的。如果它和 True 差不多,那就已经足够真了。True 还能更真吗?

为什么要创建多余的对象呢?

对于 也是一样的分析。

为什么要转换成布尔值?它已经足够真或足够假了。还能更真吗?


试试这个。

>>> False and 0
False
>>> True and 0
0
>>> (True and 0) == False
True

虽然 (True and 0) 实际上是 0,但它等于 False。在实际应用中,这已经足够假了。

如果这有问题,那么 bool(a and b) 会强制进行明确的转换。

6

这有什么其他的用法呢?

简洁性(因此也能提高清晰度,只要你习惯了,因为它并没有牺牲可读性!)在你需要检查某个条件时,如果条件为真就用这个值,如果为假就用另一个值(这适用于 and,如果是 or 就反过来用)。我故意不提具体的关键词,比如 TrueFalse,因为我说的是所有对象,而不仅仅是布尔值!

在电脑屏幕上,垂直空间是有限的,所以如果可以的话,最好把这些空间用在有用的可读性辅助上(比如文档字符串、注释、适当放置的空行来分隔代码块等),而不是把一行代码:

inverses = [x and 1.0/x for x in values]

变成六行,像这样:

inverses = []
for x in values:
    if x:
        inverses.append(1.0/x)
    else:
        inverses.append(x)

或者更拥挤的版本。

那么,这种实现方式的理由是什么呢?感觉有点不直观。

其实并不是“不可理解”,初学者常常会被一些语言(比如标准的Pascal)搞糊涂,因为这些语言并没有明确规定运算的顺序和短路特性;Turbo Pascal和语言标准之间的一个区别,就是Turbo在处理 andor 时,和后来的Python很相似(而C语言则更早就这样做了)。

撰写回答