6

首先,代码:

>>> False or 'hello'
'hello'

这种令人惊讶的行为使您可以检查是否x不是None并检查x一行中的值:

>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...

说明:这样or的功能:

如果 x 为假,则为 y,否则为 x

我知道的任何语言都不允许您这样做。那么,为什么要 Python 呢?

4

6 回答 6

14

听起来您将两个问题合二为一。

首先是短路问题。Marcin 的回答完美地解决了这个问题,所以我不会尝试做得更好。

其次,存在orand返回最后评估的值,而不是将其转换为布尔值。两种方式都有争论,您可以在分歧的任何一方找到许多语言。

返回最后评估的值允许使用functionCall(x) or defaultValue快捷方式,避免可能浪费的转换(如果您要做的唯一事情是检查它是否非零,为什么要将其转换int 2为 a ?),并且通常更容易解释。bool 1因此,由于这些原因的各种组合,C、Lisp、Javascript、Lua、Perl、Ruby 和 VB 等语言都以这种方式做事,Python 也是如此。

始终从运算符返回布尔值有助于捕获一些错误(尤其是在逻辑运算符和位运算符容易混淆的语言中),并且它允许您设计一种语言,其中布尔检查是严格类型检查true而不是只检查非零,它使运算符的类型更容易写出,并且避免了在两个操作数是不同类型的情况下处理转换(参见?:C 系列语言中的运算符)。因此,由于这些原因的各种组合,C++、Fortran、Smalltalk 和 Haskell 等语言都以这种方式做事。


在您的问题中(如果我理解正确的话),您正在使用此功能来编写如下内容:

if (x or 0) < 1:

什么时候x可以轻松None。这个特殊的用例不是很有用,既因为更明确的x if x else 0(在 Python 2.5 和更高版本中)同样容易编写并且可能更容易理解(至少 Guido 是这么认为的),而且因为无论如何None < 1都是一样的0 < 1(至少在 Python 2.x 中,所以你总是至少有两个选项中的一个)……但也有类似的例子,它很有用。比较这两个:

return launchMissiles() or -1

return launchMissiles() if launchMissiles() else -1

第二个将浪费大量导弹在南极洲炸毁你的敌人两次而不是一次。


如果你好奇为什么 Python 会这样做:

回到 1.x 时代,没有类型bool。你有虚假的价值,比如None, 0, [], (),""等等,其他的都是真的,那么谁需要明确False的 andTrue呢?返回1fromor会很愚蠢,因为1它不比[1, 2, 3]or更真实"dsfsdf"。到bool添加的时候(逐渐超过两个 2.x 版本,IIRC),当前的逻辑已经牢固地嵌入到语言中,并且更改会破坏很多代码。

那么,他们为什么不在 3.0 中更改它呢?许多 Python 用户,包括 BDFL Guido,建议您不要or在这种情况下使用(至少因为它违反了“TOOWTDI”);您应该将表达式的结果存储在变量中,例如:

missiles = launchMissiles()
return missiles if missiles else -1

事实上,Guido 已经表示他想禁止launchMissiles() or -1,这也是他最终接受他之前多次拒绝的三元表达式if的部分原因。else但许多其他人不同意,Guido 是一个 仁慈的DFL。此外,or按照您在其他地方所期望的方式工作,同时在这里拒绝做您想做的事(但 Guido 不希望您做),实际上会非常复杂。


因此,在这里,Python 可能总是与 C、Perl 和 Lisp 站在同一边,而不是与 Java、Smalltalk 和 Haskell 站在同一边。

于 2012-12-13T23:52:53.027 回答
10

没有我知道的语言可以让你这样做。那么,为什么 Python 会这样做呢?

那么你不会很多语言。我想不出我知道的一种语言不会表现出这种“短路”行为。

这样做是因为这样说很有用:

a = b or K

这样 a 要么变成 b,如果 b 不是 None (或否则是假的),如果不是,它得到默认值 K。

于 2012-12-13T23:33:05.993 回答
6

实际上,许多语言都可以。参见关于短路评估的维基百科

出于短路评估存在的原因,维基百科写道

如果用作条件的两个表达式都是简单的布尔变量,则实际上一次计算布尔运算中使用的两个条件会更快,因为它总是需要一个计算周期,而不是短路计算中使用的一个或两个周期(取决于第一个的值)。

于 2012-12-13T23:31:43.353 回答
3

这种行为并不奇怪,如果您认为 Python 具有以下关于orand not逻辑运算符的特性,那就很简单了:

  • 短路评估:它只评估操作数到它需要的地方。
  • 非强制结果:结果是操作数之一,不强制为bool.

而且,另外:

  • 对象的真值仅对, , , , ,为False。其他所有内容的真值均为True这是一种简化;正确的定义在官方文档中)NoneFalse0""[]{}

结合这些特征,它会导致:

  • or:如果第一个操作数的计算结果为True,则在此处短路并返回它。或返回第二个操作数。
  • and:如果第一个操作数的计算结果为False,则在此处短路并返回它。或返回第二个操作数。

如果您概括为一系列操作,则更容易理解:

>>> a or b or c or d

>>> a and b and c and d

这是我记住的“经验法则”,可帮助我轻松预测结果:

  • or:返回它找到的第一个“ truthy操作数,或者最后一个。
  • and : 返回它找到的第一个“ falsy操作数,或者最后一个。

至于你的问题,为什么python 会有这样的行为,嗯......我认为因为它有一些非常简洁的用途,而且理解起来非常直观。一个常见的用途是一系列后备选择,使用第一个“找到”(即非虚假)。想想这个愚蠢的例子:

drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"

或者这个真实世界的场景:

username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME

这比替代方案更简洁优雅。

正如许多其他答案所指出的那样,Python 并不孤单,许多其他语言具有相同的行为,无论是短路(我相信大多数当前语言都是)和非强制。

于 2014-06-06T12:48:50.497 回答
1

“没有我知道的语言可以让你这样做。那么,为什么 Python 会这样做呢?” 您似乎认为所有语言都应该相同。您不期望编程语言的创新能够产生人们重视的独特功能吗?

您刚刚指出了它为什么有用,那么 Python 为什么不这样做呢?也许你应该问为什么其他语言没有。

于 2012-12-13T23:46:04.373 回答
0

您可以在布尔上下文之外利用 Python 或运算符的特殊功能。经验法则仍然是布尔表达式的结果是第一个true操作数或行中的最后一个操作数。

请注意,逻辑运算符(或包含的)在赋值运算符之前计算=,因此您可以将布尔表达式的结果分配给变量,就像使用普通表达式一样:

>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}

在这里,or运算符按预期工作,返回第一个true操作数或最后一个操作数,如果两者都被评估为false

于 2021-02-02T22:20:16.907 回答