Python 条件运算符解决方法如何工作?
Posted
技术标签:
【中文标题】Python 条件运算符解决方法如何工作?【英文标题】:How does the Python conditional operator workaround work? 【发布时间】:2010-12-29 03:44:21 【问题描述】:根据我的阅读,我发现内置的三元运算符不存在(我很乐意了解更多信息。)。
我找到了以下代码作为替代:
def val():
var = float(raw_input("Age:"))
status = ("Working","Retired")[var>65]
print "You should be:",status
我无法理解这段代码是如何工作的;谁能解释一下代码实际上是如何工作的?我也很想知道为什么三元运算符不存在;任何有关此的参考或链接都会很有用。
我在 Windows Vista 上运行 Python 2.6.4。
【问题讨论】:
Python 2.5 版本增加了三元运算符 -1:请不要称其为“THE”三元运算符。它只是一个条件运算符,它恰好是(许多)三元运算之一。其他三元运算包括pow(x,y,z)
。
也许我错了,但通常运算符是“+”或“%”或(在这种情况下)“if”。即:不是函数。我不认为 pow 会被视为三元运算符,它只是一个具有三个输入的函数。 (三元运算符,是的。operator,否。)在许多语言中,像 this 这样的内联条件是唯一需要三个输入的运算符,因此是三元运算符(对于该语言),所以它确实不正确。维基救援! en.wikipedia.org/wiki/Ternary_operator
(x, y)[bool]
构造是 2.5 之前的标准习惯用法。与y if bool else x
相比,它的缺点是总是计算x
和y
,而三元运算符会将其中一项短路。
@Toji:“操作”(我使用的词)和“操作员”的区别对我来说太微妙了。许多语言在许多符号中都有许多运算符。一元和二元运算符/操作很常见。但是将这个(并且只有这个)运算符/操作称为“三元”是愚蠢的。更高元的运算符呢?这是一个糟糕的术语,并且可以通过将其称为条件运算符来轻松避免,因为它就是这样。它恰好是三元的(或具有 3 的元数),但这不是定义特征。
【参考方案1】:
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,他心软了,添加了上面看到的语法。
【讨论】:
我记得坐在 OSCON keynote 中,Guido 谈到了他没有将三元运算符放入 Python 的原因。想一想,大量不同的开发人员和技术人员以及演讲者正在谈论 30 年前的旧新闻并且没有实现的语言特定功能的微小细节。没有试图提出更广泛的观点。我经历过的最无聊的主题演讲。【参考方案2】: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'
【讨论】:
请注意,这仅在 2.5 或更高版本中可用。旧版本中没有类似的东西。 @Pace 是的,尽管提问者提到他们使用的是 2.6.4。只是为了清楚起见添加了一条注释。【参考方案3】:因为 True 强制转换为 1 而 False 强制强制转换为 0 所以如果 var = 70
("Working","Retired")[var>65]
变成
("Working", "Retired")[1]
一个不错的小捷径......但我发现除了简单的条件之外,它可能会让人有点困惑,所以我会接受 TM 的建议
"Retired" if var > 65 else "Working"
【讨论】:
【参考方案4】:索引到列表中
使用
[expression_when_false, expression_when_true][condition] # or
(expression_when_false, expression_when_true)[condition]
利用了在 Python 中 True 等于(但不是!)1 和 False 等于(但不是!)0 的事实。上面的表达式构造了一个包含两个元素的列表,并使用了 condition 在列表中建立索引并仅返回一个表达式。这种方法的缺点是两个表达式都被计算了。
和-或快捷方式
自从 Python 创建以来,就有了这种操作的一种形式:
condition and expression_when_true or expression_when_false
这采用了一条捷径并且只计算一个表达式,但有一个容易出错的缺点:expression_when_true 不得计算为非真值,否则结果是 expression_when_false。 and
和 or
在 Python 中是“短路”,适用以下规则:
a and b #→ a if a is false, else b
a or b #→ a if a is true, else b
如果 condition 为 false,则永远不会评估 expression_when_true,结果为 expression_when_false。 OTOH,如果 condition 为真,则结果为 (expression_when_true 或 expression_when_false) 的结果;请参阅上表。
三元条件运算符
当然,从 Python 2.5 开始,就有了三元条件运算符:
expression_when_true if condition else expression_when_false
操作数的奇怪顺序(如果您习惯于类似 C 的三元条件运算符)归因于 to many things;总体意图是 condition 在大多数情况下都应该为真,以便最常见的输出首先出现并且最明显。
【讨论】:
【参考方案5】:短路布尔表达式
还有一个短路逻辑操作的选项:
>>> (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: Functional Programming in Python, Part 1 中了解有关此技术的更多信息。
【讨论】:
【参考方案6】:在您发布的代码中,以下行模拟三元:
status = ("Working","Retired")[var>65]
这里的元组("Working","Retired")
使用索引[var>65]
访问,其计算结果为True
(1
) 或False
(0
)。当使用索引0
访问它时,status
将是'Working'
;如果索引是1
,那么它将被“退休”。这是进行条件赋值的一种相当晦涩的方法,如前所述,使用 py2.5 中引入的正常三元语法。
【讨论】:
【参考方案7】:最初没有三元运算符,因为“显式优于隐式”,因此被视为非pythonic。我也不太喜欢python的三元运算,但它确实存在:
x = foo if condition else bar
如 TM 所示。
至于status = ("Working","Retired")[var>65]
,
var > 65
返回一个布尔值:True 或 False;但是,Python 对布尔类型的处理非常弱:在某些情况下,True
是 1
和 False
是 0
。你可以通过>>> True == 1
查看。
【讨论】:
【参考方案8】: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"
。
【讨论】:
【参考方案9】:只有该代码的“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() 是否具有“副作用”尤其重要,这意味着它们在执行时会更改其他数据。
【讨论】:
【参考方案10】:在 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"))
【讨论】:
在您的第一个示例中,Python 2.5 没有这种字符串格式。 啊,谢谢;我从佩斯的评论中获取了这个信息到另一个答案 - 你是对的,.format()
是在 2.6 中引入的。【参考方案11】:
这是带有python三元运算符的形式
def val():
var = float(raw_input("Age:"))
status = "Retired" if var > 65 else "Working"
print "You should be:",status
您展示的代码有点棘手:它创建了一个两个元素的元组,其元素位于位置 0 和 1。要选择正确的元素,它使用返回布尔值的条件,但 python 中的布尔值是整数,因此您可以使用它作为 special 索引(它们可以是 0 或 1)。
【讨论】:
糟糕。你的三元条件是相反的。一个很好的例子,说明为什么您会选择使用其他结构来清楚说明。 不幸的是,像这样简单的布尔逻辑总是很容易在不经意间翻转,无论其格式如何。我不认为三元真的和它有任何关系。 jmanning2k:我将答案恢复为初始形式,因为它已经正确。把它想象成一个英文短语:“如果你超过 65 岁,你应该退休,否则工作。”【参考方案12】:尝试根据此处给出的答案给出完整的答案。
你找到的方式(请不要使用这个,因为它不太可读):
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+ 三元运算符,因为它简单、易读并且提供短路行为。
【讨论】:
我不敢相信人们一直在建议 and-or hack。它们是不等价的,因为 and-or 技巧有一些令人讨厌的极端情况,它不能按预期工作。 (我不是因为你是为了完整而回答你,而是为了完整而发表评论,以警告你不要这样做。) and-or hack 有一个唯一的优势,那就是它允许短路行为。虽然使用它的风险通常太大(最大的是程序员不理解它,第二大的是下一个程序员不会理解它)。 此答案中的第二个和第三个示例交换了“工作”和“退休”,这给出了错误的答案。试试这个:status = "Retired" if var>65 else "Working"
.以上是关于Python 条件运算符解决方法如何工作?的主要内容,如果未能解决你的问题,请参考以下文章
Python中使用逻辑与运算符“and”判断两个比较条件是否满足时编辑器提示“Simplify chained comparison ”的解决方法
如何解决“无法无条件调用运算符‘0’,因为接收者可以为‘null’”[重复]
Python Selenium:如何在预期条件下应用“与”逻辑运算符