20

在 python 中,如果你写类似的东西

foo==bar and spam or eggs

如果布尔语句为真,python 似乎返回垃圾邮件,否则返回鸡蛋。有人可以解释这种行为吗?为什么表达式不像一个长布尔值那样被评估?

编辑:具体来说,我试图弄清楚为什么“垃圾邮件”或“鸡蛋”作为表达式的结果被返回的机制。

4

4 回答 4

20

运算符andor是短路的,这意味着如果表达式的结果可以从仅计算第一个操作数推导出来,则不计算第二个操作数。例如,如果您有表达式a or b并且a计算结果为 true,那么不管是什么b,表达式的结果都是 true,因此b不会被计算。它们实际上的工作方式如下:

  • a and b: 如果 a 为假,则不计算 b 并返回 a,否则返回 b。
  • a or b: 如果 a 为真,则不计算 b 并返回 a,否则返回 b。

Falsey 和truthy 是指在布尔上下文中评估为假或真的值。

然而,这个和/或成语在没有更好的选择的日子里很有用,但现在有更好的方法:

spam if foo==bar else eggs

和/或成语的问题(除了让初学者感到困惑之外)是如果条件为真但垃圾邮件评估为假值(例如空字符串),它会给出错误的结果。出于这个原因,你应该避免它。

于 2010-07-05T20:18:30.857 回答
6

这就是 Python 布尔运算符的工作方式。

文档中(最后一段解释了为什么操作员按照他们的方式工作是个好主意):

在布尔运算的上下文中,以及当控制流语句使用表达式时,以下值被解释为 false: False, None, 所有类型的数字零,以及空字符串和容器(包括字符串、元组、列表、字典、集合和冻结集)。所有其他值都被解释为 true。(有关 __nonzero__()更改此设置的方法,请参见特殊方法。)

如果其参数为假,则运算符not产生,否则。TrueFalse

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

表达式x or y首先计算 x; 如果x为真,则返回其值;否则,评估 y 并返回结果值。

(注意,既不限制and也不or限制它们返回的值和类型 FalseTrue而是返回最后评估的参数。这有时很有用,例如,如果s是一个字符串,如果它是空的,则应该用默认值替换,表达式s or 'foo'产生期望的值。因为not无论如何都必须创造一个值,所以它不会费心返回与其参数相同类型的值,例如,not 'foo'yield False,而不是''。)

于 2010-07-05T20:18:55.353 回答
3

原因是 Python 使用所涉及变量的实际值来评估布尔表达式,而不是将它们限制为TrueFalse值。以下值被认为是错误的:

  • None
  • False
  • 任何数字类型的 0
  • 空序列或集合 ( '', (), [], {})
  • 具有返回 0 或方法的__nonzero__()或方法的用户定义类型__len__()False

有关更多信息,请参阅 Python 文档的真值测试部分。尤其:

除非另有说明,否则具有布尔结果的操作和内置函数始终返回0False为假和1或为真。True(重要的例外:布尔运算总是返回它们orand操作数之一。)

于 2010-07-05T20:16:28.083 回答
2

尝试使用括号使表达式明确。就这样,你得到:

(foo == bar and spam) or eggs
于 2010-07-05T20:13:35.687 回答