Python中的布尔运算(即:与/或运算符)
这个方法会寻找第一个由字母、数字或下划线组成的字符组(也就是 [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 个回答
简单来说,a and b
会返回一个和整个表达式真值相同的操作数。
这听起来可能有点复杂,但你可以在脑海中想象一下:如果 a
是 False
,那么 b
就不重要了(因为 False and 任何东西
永远都是 False
),所以它可以直接返回 a
。
但是当 a
是 True
的时候,只有 b
才重要,所以它会直接返回 b
,甚至都不需要看。
这是很多编程语言都会做的一种非常常见且基本的优化。
这还有什么其他的用法呢?
没有。
这个实现方式听起来不太直观,为什么会这样呢?
“不直观”?真的?我不同意。
我们来想想。
当我们说“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)
会强制进行明确的转换。
这有什么其他的用法呢?
简洁性(因此也能提高清晰度,只要你习惯了,因为它并没有牺牲可读性!)在你需要检查某个条件时,如果条件为真就用这个值,如果为假就用另一个值(这适用于 and
,如果是 or
就反过来用)。我故意不提具体的关键词,比如 True
和 False
,因为我说的是所有对象,而不仅仅是布尔值!
在电脑屏幕上,垂直空间是有限的,所以如果可以的话,最好把这些空间用在有用的可读性辅助上(比如文档字符串、注释、适当放置的空行来分隔代码块等),而不是把一行代码:
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在处理 and
和 or
时,和后来的Python很相似(而C语言则更早就这样做了)。