11

此方法搜索第一组单词字符(即:)[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为假,则返回其值;否则,y评估并返回结果值。

但是,作为一个布尔运算符(它甚至在手册上这么说),我希望and返回一个布尔值。结果,当我发现它(如何)起作用时 ,我感到很惊讶。

这还有哪些其他用例,和/或这种相当不直观的实现的基本原理是什么?

4

5 回答 5

6

还有什么其他用例,

简洁(因此清晰,一旦你习惯了它,因为毕竟它根本不会牺牲可读性!-)任何时候你需要检查一些东西,如果它是真的就使用那个东西,或者如果那个东西是另一个值是假的(那是为了and——把它倒过来or——而且我非常刻意地避免使用实际的关键字或类似的Trueand False,因为我在谈论每个对象,而不仅仅是bool!-)。

任何计算机屏幕上的垂直空间都是有限的,如果可以选择,最好将其用于有用的可读性辅助工具(文档字符串、注释、策略性地放置空行以分隔块……),而不是转动诸如以下之类的行:

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)没有指定and评估顺序和and的短路性质or;Turbo Pascal 和语言标准之间的差异之一,在当时使 Turbo 成为有史以来最流行的 Pascal 方言,正是 Turbo 实现的andor很像 Python 后来做的(而 C 语言更早做......) .

于 2010-09-30T03:39:34.467 回答
4

还有什么其他用例,

不。

这种相当不直观的实施的理由是什么?

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

让我们想想。

"a and b" 如果为假,a则为假。所以第一个假值就足以知道答案了。为什么要麻烦转换a为另一个布尔值?已经是假的了。还有多少是假的False?同样是假的,对吧?

所以a's 的值——当等价于False——是足够假的,所以这就是整个表达式的值。没有进一步的转换或处理。完毕。

a' 值等于Truethen b' 值是所有需要的。没有进一步的转换或处理。为什么要转换b为另一个布尔值?我们只需要知道它的价值。如果它是类似的True,那么它就足够了。更真实的是True多少?

为什么要创建虚假的附加对象?

相同的分析or

为什么要转换为布尔值?它已经足够真实或足够虚假。它还能得到多少真实?


试试这个。

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

虽然(True and 0)实际上是0,但它等于False。这对于所有实际目的来说都是错误的。

如果这是一个问题,那么bool(a and b)将强制显式转换。

于 2010-09-30T00:10:23.143 回答
1

基本上a and b返回与整个表达式具有相同真值的操作数。

这可能听起来有点混乱,但只要在你的脑海中做:如果aFalse,那么b不再重要(因为False and anything将永远是False),所以它可以a立即返回。

但是什么时候才是a最重要的,所以它甚至不看就立即返回。Truebb

这是许多语言所做的非常常见且非常基本的优化。

于 2010-09-29T23:56:20.917 回答
0

我并不觉得这令人惊讶,事实上,当我最初尝试它时,我就期望它会起作用。

虽然并非所有值都是bools,但请注意,实际上,所有值都是布尔值——它们代表一个真值。(在 Python 中,abool是——实际上——一个表示真或假的值。)该数字0不是布尔值,但它(在 Python 中)显式地具有布尔值 False。

换句话说,布尔运算符and并不总是返回 a bool,但它总是返回一个布尔值;代表真或假的一个,即使它还具有逻辑上附加的其他信息(例如字符串)。

也许这是追溯性的理由;我不确定,但无论哪种方式,Python 的布尔运算符的行为似乎都很自然。


什么时候使用它?

在您的示例中, test2 对我来说感觉更清晰。我可以告诉他们两者都做同样的事情:test2 中的构造并没有使它更难理解。在其他条件相同的情况下,test2 中的代码越简洁——在某种程度上——越容易被理解。也就是说,这是一个微不足道的区别,我不太喜欢我会跳到重写任何东西。

它在其他方面也同样有用:

a = {
    "b": a and a.val,
    "c": b and b.val2,
    "d": c and c.val3,
}

这可以用不同的方式重写,但这是清晰、直接和简洁的。

不要过火;"a() and b() or c()" 作为 "a()? b():c()" 的替代是危险和令人困惑的,因为如果 b() 是,你最终会得到 c()错误的。如果您正在编写三元语句,请使用三元语法,即使它非常难看:b() if a() else c().

于 2010-09-29T23:47:49.570 回答
0

我认为虽然这种表示法“有效”,但它代表了一种糟糕的编码风格,它隐藏了逻辑,并且会使更有经验的程序员感到困惑,他们将“包袱”了解大多数其他语言是如何工作的。

在大多数语言中,活动函数的返回值由函数的类型决定。除非它被显式重载。示例 'strlen' 类型函数应返回整数而不是字符串。

诸如核心关节炎和逻辑函数 (+-/*|&!) 之类的在线函数更加受限,因为它们背后也有形式数学理论的历史。(想想关于这些函数的操作顺序的所有论点)

让基本函数返回除它们最常见的数据类型(逻辑或数字)之外的任何内容都应归类为有目的的混淆。

在几乎每一种通用语言中,'&' 或 '&&' 或 'AND' 都是逻辑或布尔函数。在幕后,优化编译器可能会在 LOGIC FLOW 中使用上述捷径逻辑,但不会使用 DATA STRUCTURE 修改(任何以这种方式更改值的优化编译器都将被视为损坏),但如果预期该值将用于变量为了进一步处理,它应该是逻辑或布尔类型,因为在大多数情况下,这是这些运算符的“正式”类型。

于 2014-11-26T17:30:35.670 回答