21

根据我的阅读,我发现不存在内置的三元运算符(我很乐意了解更多信息。)。

我找到了以下代码作为替代:

def val():
    var = float(raw_input("Age:"))
    status = ("Working","Retired")[var>65]
    print "You should be:",status

我无法理解这段代码是如何工作的;谁能解释一下代码实际上是如何工作的?我也很想知道为什么三元运算符不存在;任何有关此的参考或链接都会很有用。

我在 Windows Vista 上运行 Python 2.6.4。

4

12 回答 12

51

Python 有一个结构,有点像 C 中的三元运算符等。它的工作原理是这样的:

my_var = "Retired" if age > 65 else "Working"

并且等效于以下 C 代码:

my_var = age > 65 ? "Retired" : "Working";

至于您发布的代码是如何工作的,让我们逐步介绍一下:

("Working","Retired")

创建一个 2 元组(一个不可变列表),索引 0 为元素“Working”,索引 1 为“Retired”。

var>65

如果 var 大于 65,则返回 True,否则返回 False。应用于索引时,它会转换为 1 (True) 或 0 (False)。因此,这个布尔值提供了在同一行上创建的元组的索引。

为什么 Python 不是一直都有三元运算符?简单的答案是 Python 的作者 Guido van Rossum 不喜欢/不想要它,显然认为它是一种不必要的构造,可能导致混淆代码(以及任何在C 可能会同意)。但是对于 Python 2.5,他让步了,并添加了上面看到的语法。

于 2009-12-22T15:31:54.327 回答
9

Python(2.5 及更高版本)确实具有您正在寻找的语法:

x = foo if condition else bar

如果condition为 True,x则设置为foo,否则设置为bar

例子:

>>> age = 68
>>> x = 'Retired' if age > 65 else 'Working'
>>> x
'Retired'
>>> age = 35
>>> y = 'Retired' if age > 65 else 'Working'
>>> y
'Working'
于 2009-12-22T15:24:40.727 回答
8

因为 True 强制转换为 1 而 False 强制转换为 0 所以如果 var = 70

("Working","Retired")[var>65]

变成

("Working", "Retired")[1]

一个不错的小捷径......但我发现除了简单的条件之外,它可能会让人有点困惑,所以我会接受 TM 的建议

"Retired" if var > 65 else "Working"
于 2009-12-22T15:31:01.163 回答
7

索引到列表中

指某东西的用途

[expression_when_false, expression_when_true][condition] # or
(expression_when_false, expression_when_true)[condition]

利用 Python 中 True 等于(但不是!)1 和 False 等于(但不是!)0 的事实。上面的表达式构造了一个包含两个元素的列表,并使用条件的结果来索引列出并仅返回一个表达式。这种方法的缺点是两个表达式都被计算。

和-或快捷方式

自从 Python 创建以来,就有了这种操作的一种形式:

condition and expression_when_true or expression_when_false

这采用了一条捷径,只计算一个表达式,但有一个容易出错的缺点:expression_when_true 不能计算为非真值,否则结果是expression_when_falseand并且or在 Python 中是“短路”的,并且适用以下规则:

a and b #→ a if a is false, else b
a or b  #→ a if a is true, else b

如果条件为假,则永远不会评估expression_when_true并且结果为expression_when_false。OTOH,如果条件为真,则结果为(expression_when_trueexpression_when_false)的结果;请参阅上表。

三元条件运算符

当然,从 Python 2.5 开始,就有了一个三元条件运算符:

expression_when_true if condition else expression_when_false

操作数的奇怪顺序(如果您习惯于类似 C 的三元条件运算符)归因于很多事情;一般的意图是条件在大多数情况下应该为真,以便最常见的输出首先出现并且最明显。

于 2009-12-22T20:32:04.290 回答
2

短路布尔表达式

还有一个短路逻辑操作的选项:

>>> (2+2 == 4) and "Yes" or "No"
'Yes'
>>> (2+2 == 5) and "Yes" or "No"
'No'

在您的示例中:

>>> (int(raw_input("Age: ")) > 65) and "Retired" or "Working"
Age: 20
'Working'
>>> (int(raw_input("Age: ")) > 65) and "Retired" or "Working"
Age: 70
'Retired'

在Charming Python:Python 中的函数式编程,第 1 部分中阅读有关此技术的更多信息。

于 2009-12-28T11:17:44.997 回答
0

在 Python 2.6 及更高版本中:

print "You should be {0}.".format("retired" if var>65 else "working")

在 Python 3.1 及更高版本中:

print ("You should be {}.".format("retired" if var>65 else "working"))
于 2009-12-22T15:29:43.120 回答
0

在您发布的代码中,以下行模拟三元:

status = ("Working","Retired")[var>65]

此处的元组使用计算结果为( ) 或( )("Working","Retired")的索引访问。当它使用 index 访问时,将是; 如果 index 是,那么它将被“退休”。这是进行条件赋值的一种相当晦涩的方法,如前所述,使用 py2.5 中引入的正常三元语法。[var>65]True1False00status'Working'1

于 2009-12-22T15:31:28.017 回答
0

这是带有 python 三元运算符的形式

def val():
    var = float(raw_input("Age:"))
    status = "Retired" if var > 65 else "Working"
    print "You should be:",status

您显示的代码有点棘手:它创建了一个两个元素的元组,其元素位于位置 0 和 1。要选择正确的元素,它使用返回布尔值的条件,但 python 中的布尔值是整数,因此您可以将其用作特殊值索引(它们可以是 0 或 1)。

于 2009-12-22T15:32:16.860 回答
0

最初没有三元运算符,因为“显式优于隐式”,因此被视为非pythonic。我也不太喜欢python的三元运算,但它存在:

x = foo if condition else bar

如 TM 所示。

至于status = ("Working","Retired")[var>65]var > 65返回一个布尔值:True 或 False;但是,Python 对布尔类型的处理非常弱:在某些情况下True1False是。0您可以通过执行来检查它>>> True == 1

于 2009-12-22T15:32:52.020 回答
0
status = ("Working","Retired")[var>65]

此行用作三元运算符,因为表达式var>65返回 1 或 0,具体取决于是否var大于 65。因此,如果var>65,则该行变为:

status = ("Working","Retired")[1]

即序列的第二个元素("Working","Retired")。它看起来很奇怪,但如果你这样写它就不会:

status_sequence = ("Working","Retired")
status = status_sequence[1]

所以status = "Retired"

同样,如果var<=65那么它变成

status = ("Working","Retired")[0]

status = "Working"

于 2009-12-22T15:34:53.030 回答
0

只有该代码的“status =”行实现了类似于三元运算符的东西。

status = ("Working","Retired")[var>65]

这将创建一个包含两个元素的元组,字符串“Working”在索引 0 处,“Retired”在索引 1 处。在此之后,它使用表达式的结果对该元组进行索引以选择两个项目之一var > 65

如果 var 的值大于 65,则此表达式将返回 True(等于 1,因此选择“Retired”)。否则它将返回 False(等于 0,因此选择“Working”)。

但是,这种方法与三元运算符之间存在一个关键区别,尽管在您的特定示例中并不重要。使用元组索引方法,两个值都被评估但只返回一个。使用三元运算符,实际上只计算两个值中的一个;这被称为“短路”行为。在这种情况下可能很重要:

status = funcA() if var > 65 else funcB()
status = (funcB(), funcA())[var > 65]

在第一种情况下,要么调用 funcA(),要么调用funcB (),但绝不会同时调用两者。在后一种情况下,首先调用两者,并将结果存储在元组中——然后只选择一个并且丢弃元组。

这对于了解 funcA() 或 funcB() 是否具有“副作用”尤其重要,这意味着它们在执行时会更改其他数据。

于 2009-12-22T15:35:37.333 回答
0

试图根据此处给出的答案给出完整的答案。

你找到的方式(请不要使用这个,因为它不是很可读):

def val():
    var = float(raw_input("Age:"))
    status = ("Working","Retired")[var>65]
    print "You should be:",status

使用 python 2.5+ 语法:

def val():
    var = float(raw_input("Age:"))
    status = "Working" if var>65 else "Retired"
    print "You should be:",status

使用某些人仍然喜欢的其他常用方法:

def val():
    var = float(raw_input("Age:"))
    status = var>65 and "Working" or "Retired"
    print "You should be:",status

我个人倾向于使用最后一个,因为操作数的顺序与 C 三元运算符相同。

编辑: 发现最后一种方法存在一些问题(谢谢 Roberto Bonvallet)。
来自维基百科:

如果 op1 可能是“假”值(无、假、0、空序列或集合……),则此代码将中断,因为表达式将返回 op2(无论是真还是假)而不是(假)op1

所以我最后的建议是使用 2.5+ 三元运算符,因为它简单、易读并且提供短路行为。

于 2009-12-22T15:39:14.147 回答