首先,代码:
>>> 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 呢?
听起来您将两个问题合二为一。
首先是短路问题。Marcin 的回答完美地解决了这个问题,所以我不会尝试做得更好。
其次,存在or
并and
返回最后评估的值,而不是将其转换为布尔值。两种方式都有争论,您可以在分歧的任何一方找到许多语言。
返回最后评估的值允许使用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
呢?返回1
fromor
会很愚蠢,因为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 站在同一边。
没有我知道的语言可以让你这样做。那么,为什么 Python 会这样做呢?
那么你不会很多语言。我想不出我知道的一种语言不会表现出这种“短路”行为。
这样做是因为这样说很有用:
a = b or K
这样 a 要么变成 b,如果 b 不是 None (或否则是假的),如果不是,它得到默认值 K。
实际上,许多语言都可以。参见关于短路评估的维基百科
出于短路评估存在的原因,维基百科写道:
如果用作条件的两个表达式都是简单的布尔变量,则实际上一次计算布尔运算中使用的两个条件会更快,因为它总是需要一个计算周期,而不是短路计算中使用的一个或两个周期(取决于第一个的值)。
这种行为并不奇怪,如果您认为 Python 具有以下关于or和and not逻辑运算符的特性,那就很简单了:
bool
.而且,另外:
None
False
0
""
[]
{}
结合这些特征,它会导致:
如果您概括为一系列操作,则更容易理解:
>>> a or b or c or d
>>> a and b and c and d
这是我记住的“经验法则”,可帮助我轻松预测结果:
至于你的问题,为什么python 会有这样的行为,嗯......我认为因为它有一些非常简洁的用途,而且理解起来非常直观。一个常见的用途是一系列后备选择,使用第一个“找到”(即非虚假)。想想这个愚蠢的例子:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
或者这个真实世界的场景:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
这比替代方案更简洁和优雅。
正如许多其他答案所指出的那样,Python 并不孤单,许多其他语言具有相同的行为,无论是短路(我相信大多数当前语言都是)和非强制。
“没有我知道的语言可以让你这样做。那么,为什么 Python 会这样做呢?” 您似乎认为所有语言都应该相同。您不期望编程语言的创新能够产生人们重视的独特功能吗?
您刚刚指出了它为什么有用,那么 Python 为什么不这样做呢?也许你应该问为什么其他语言没有。
您可以在布尔上下文之外利用 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
。