DDR爱好者之家 Design By 杰米

(1) variable = a if exper else b
(2)variable = (exper and [b] or [c])[0]
(2) variable = exper and b or c

上面三种用法都可以达到目的,类似C语言中 variable = exper ? b : c;即:如果exper表达式的值为true则variable = b,否则,variable = c

例如:

复制代码 代码如下:
a,b=1,2
max = (a if a > b else b)
max = (a > b and [a] or [b])[0] #list
max = (a > b and a or b)


现在大部分高级语言都支持“?”这个三元运算符(ternary operator),它对应的表达式如下:condition ? value if true : value if false。很奇怪的是,这么常用的运算符python居然不支持!诚然,我们可以通过if-else语句表达,但是本来一行代码可以完成的非要多行,明显不够简洁。没关系,在python里其实还是有对应的表达方式的。

举个例子:char *ret = (x!=0) ? "True" : "False"这行代码对应的python形式就是ret = (x and "True") or "False"(很简单吧,事实上括号可以去掉)。运行时,python虚拟机会对赋值符右边的布尔表达式(注意这里并非三元表达式)求值,返回值是最后一个被分析到的值。为什么是“最后一个被分析到的”而不是表达式中“最后一个”呢?因为布尔表达式有一个短路效应,比如a or b,如果a为真那么就不会分析b了。嗯,估计现在大家差不多明白了这行python代码的原理了。如果x为真,由于字符串“True”也为真,于是返回"True",反之,x为假,那么就没必要看字符串"True"了(短路效应),直接返回"False"。

不难看出,三元运算在python中事实上可以通过借用布尔求值表达。然后,有时会有点小问题。举个例子,char *ret = x ? "" or "VAL"。根据前面的例子,我们很自然想到在python里应该这样写,ret = x and "" or "VAL"。错了!不管x的布尔求值是真还是假,ret得到的总是"VAL"。奇怪么?不奇怪,因为在python中对空字符串的布尔求值为false,这样x and ""永远都是false,所以ret得到的自然总是"VAL"了。解决这个问题有两种办法,第一种,也是我喜欢的一种,就是写成ret = not x and "VAL" or ""。第二种,麻烦一点ret=x and [""] or ["VAL"],然后每次取ret[0]作为返回值,这是因为[""]在布尔求值时值为true。

讨论一:第一种方法代码明显要简洁,效率也高,那么还有必要使用第二种么?当然,第一种办法有局限性,只有当我们非常明确其中一个值布尔求值时不可能为false时才能使用。在我们的示例中,由于"VAL"肯定返回true所以可以使用。如果是两个变量呢,像这样ret=x and val1 or val2,你就只能老老实实写成ret=x and [val1] or [val2],然后取ret[0]作为结果了。因为这行语句所表达的不是“当x为真返回val1,否则返回val2”,而是“当x为真并且val1为真返回val2,否则返回val2”。

讨论二:大家都知道python里有list和tuple,前面这行代码ret=x and [""] or ["VAL"]我们就是通过list解决,有的人可能偏爱tuple,于是就会这样写ret=x and ("") or ("VAL")。错了!这里ret[0]永远都是空字符串(在2.5上测试)。这是我比较faint的一点,为啥[""]为真而("")为假呢?

最后,附上python对典型数值的布尔求值结果,这对我们书写三元运算的等价语句很有用。

输入 布尔求值 1,-1,[“”] True 0, “”, None, [], (), {}, (“”) False

python 三元表达式

之前学习的Python提到了对于类似C语言的三元条件表达式condition ? true_part : false_part,虽然Python没有三目运算符(?:),但也有类似的替代方案,那就是true_part if condition else false_part。

复制代码 代码如下:
> 1 if True else 0
1
> 1 if False else 0
0
> "Fire" if True else "Water"
'Fire'
> "Fire" if False else "Water"
'Water'

在编程中我也一直这么用了,直到有一天发现了一个有趣的技巧,那就是and-or技巧,利用条件判断的优先特性来实现三元条件判断,比如P∧Q,在Python中如果P为假,那么Python将不会继续执行Q,而直接判定整个表达式为假(P值),当然如果P为真,那就还要继续执行Q来决定整个表达式值;同样的P∨Q,如果P为真,那么就不会继续执行Q了…

其实很多编程语言在逻辑判断中都应用了这套机制,目前我接触下来的貌似VB/VBScript可能不是这么做的。有了这套机制除了在if判断中提高效率外,我们还可以额外发掘一些有趣的功能,比如下面的PHP代码:

复制代码 代码如下:
$conn = @mysql_connect(...) or die("Failed")

如果mysql_connect成功的话将会返回resource资源句柄,如果失败的话将会返回False,等等,后面还有个or,也就是失败的话还将会继续执行or后面的die语句,于是输出了错误信息并终止后续代码的执行。

再如下面的JavaScript代码:

复制代码 代码如下:
function getEvent(e) {
    e = e || window.event;
    return e;
}

这段代码获取的是event,假如没有给getEvent传入值(即e为undefined),或者e为NULL(两者在JavaScript条件中均代表False),e = e || window.event表达式将会把window.event赋值给e,否则e为Object对象,原表达式会蜕化为e = e赋值,也就是没有改变什么。

好了,扯了这么多,稍稍有些偏题了,下面继续聊Python的and-or技巧,可以这么说,这个技巧也是利用了逻辑判断的特殊性,貌似在真正的三元表达式if else没有出来的时候其就一直在扮演三元表达式的角色,其原型是condition and true_part or false_part,下面举几个例子:

复制代码 代码如下:
> True and 1 or 0
1
> False and 1 or 0
0
> True and "Fire" or "Water"
'Fire'
> False and "Fire" or "Water"
'Water'

但是值得注意的是虽然表面看上去能够正常工作,其实还潜藏有不可知的风险,若我们的true_part本身就是个被Python认定为False的值,这个技巧就不可用了,我们知道空字符串就是这种情况。

复制代码 代码如下:
> True and "" or "Water"
'Water'

上面的表达式其实我们期望返回空字串的,如何解决呢,我在Dive Into Python中找到了解决方案:那就是利用列表特性,因为包含空字符串的列表其表达式值仍然为True,所以我们可以用列表先包装一下,然后等表达式判断完毕后在解包:

复制代码 代码如下:
> a = ""
> b = "Water"
> (True and [a] or [b])[0]
''

当然为了避免出错,我们可以将其包装为函数:

复制代码 代码如下:
def iif(condition, true_part, false_part):
    return (condition and [true_part] or [false_part])[0]

现在Python已经在语言特性中加入三元条件表达式的支持了,那就是文章一开始介绍的if else写法,所以为了妥善起见,对于三元判断还是用新的if else特性吧,其实Python官方对于加入三元表达式语法也是讨论了很久的,可以参考《PEP 308 — Conditional Expressions》。

DDR爱好者之家 Design By 杰米
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
DDR爱好者之家 Design By 杰米

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。