Python中的“布尔”操作(即:和/或运算符)

时间:2010-09-29 22:53:15

标签: python boolean-expression least-astonishment

此方法搜索第一组单词字符(即:[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)

这是相同的,并且是记录在案的行为;正如this page明确指出:

  

表达式x and y首先评估x;如果x为false,则返回其值;否则,将评估y并返回结果值。

然而,作为一个布尔运算符(它甚至在手册上都这么说),我期望and返回一个布尔值。结果,当我发现(如何)这有效时,我astonished

这有什么其他用例,和/或这种相当不直观的实现的理由是什么?

5 个答案:

答案 0 :(得分:6)

  

这有什么其他用例,

简洁(因此清晰,一旦你习惯它,因为毕竟它牺牲可读性! - )任何时候你需要检查一些东西并使用那些东西如果它是真的,或者如果某些东西是假的(或者是and的那个 - 反转它为or - 并且我非常故意避免实际的关键词 - 或类似TrueFalse,因为我说的是每个对象,而不仅仅是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)指定评估顺序和{{1的短路性质 - 这一事实,初学者经常被“不直观”所困扰。 }和and; Turbo Pascal和语言标准之间的差异之一,在当天使Turbo成为有史以来最受欢迎的Pascal方言,正是Turbo实现了orand,就像Python后来做的那样(而C语言早先做过......)。

答案 1 :(得分:4)

  

这有什么其他用例,

没有。

  

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

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

让我们思考一下。

如果a为false,则

“a b”会被伪造。所以第一个假值足以知道答案。为什么还要将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)将强制进行显式转换。

答案 2 :(得分:0)

我没有发现这令人惊讶,事实上我希望它在我最初尝试时能够正常工作。

虽然并非所有值都是bools,但请注意,实际上,所有值都是 boolean - 它们代表真值。 (在Python中,bool实际上是表示true或false的值。)数字0不是bool,而是明确的(在Python中)的布尔值为False。

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

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


何时使用?

在您的示例中,test2对我来说更清晰。我可以告诉他们两者同样如此:test2中的构造并没有让它更难理解。在其他条件相同的情况下,test2中更简洁的代码 - 稍微 - 更快地理解。也就是说,这是一个微不足道的差异,我不喜欢足够的,我会跳到重写任何东西。

它可以在其他方面同样有用:

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

这可以用不同的方式重写,但这很清楚,简洁明了。

不要过火; “a()和b()或c()”代替“a()?b():c()”是危险和令人困惑的,因为如果b()是你的话,你最终会得到c()假。如果您正在编写三元语句,请使用三元语法,即使它很丑陋:b() if a() else c()

答案 3 :(得分:0)

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

这可能听起来有些令人困惑,但只是在脑海中这样做:如果aFalse,则b不再重要(因为False and anything将永远是False),因此它可以立即返回a

但当aTrue时,只有b很重要,所以它会立即返回b,而不会看。

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

答案 4 :(得分:0)

我认为虽然这种符号可以使用'它代表了一种糟糕的编码风格,隐藏了逻辑,并且会让更多有经验的程序员感到困惑,他们将拥有这样的行李'了解大多数其他语言的工作原理。

在大多数语言中,活动函数的返回值由函数类型决定。除非它被明确重载。示例a' strlen' type函数应该返回一个不是字符串的整数。

核心关节炎和逻辑功能(+ - / * |&!)等在线功能更加克制,因为它们背后还有正式数学理论的历史。 (想想关于这些函数的操作顺序的所有论点)

要使基本函数返回任何内容,但应将其最常见的数据类型(逻辑或数字)归类为有目的的混淆。

几乎所有的共同语言'&'或者'&&'或者' AND'是逻辑或布尔函数。在幕后,优化编译器可能在LOGIC FLOW中使用如上所述的短切割逻辑,但不使用数据结构修改(任何以这种方式改变值的优化编译器都会被视为已损坏),但是如果该值预期用于变量为了进一步处理,它应该是逻辑或布尔类型,因为它是“正式的”#39;对于大多数情况下的这些运营商。