个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。
本文较简单,对if语句的格式、示例、多路做了示例,以及真值测试(and、or等)介绍,最后介绍了三三元表达式(稍难理解)以及为什么要在意布尔值。文章较短,5-10分钟阅读。
目录
if语句
通用格式
示例
多路分支
真值测试
if/else三元表达式
为什么要在意布尔值
if语句
Python if语句是选取要执行的操作。这是Python中主要的选择工具,代表Python程序所拥有的大多数逻辑。
这也是首度讨论的复合语句。就像所有的Python复合语句一样,if语句可以包含其他语句,包括其他if在内。事实上,Python让你在程序中按照顺序组合语句(使其逐一执行),而且可以任意地扩展嵌套(使其只在特定情况下执行)。
通用格式
Python的if语句是多数面向过程语言中的典型的if语句。其形式是if测试,后面跟着一个或多个可选的elif("else if")测试,以及一个最终可选的else块。
测试和else部分都有一个相关的嵌套语句块,缩进列在首行下面。当if语句执行时,Python会执行测试第一个计算结果为真的代码块,或者如果所有测试都为假时,就执行else块。if语句的一般形式如下。
示例
除了开头的if测试及其相关联的语句外,其他所有部分都是选用的。
>>> if 1:
print('True')
True
>>>
注意:当在这里使用交互模式(CMD窗口进入python)输入时,提示符在接下去的行中变成...(在IDLE中,你只会直接向下到缩进的行,点击Backspace可以返回)。
空白行将终止并执行整个语句。1是布尔真值,所以这个测试永远会成功。要处理假值结果,可改写成下面的程序:
>>> if not 1:
print('True')
else:
print('False')
False
多路分支
下面是更为复杂的if语句例子,其所有选用的部分都存在:
>>> if x == 'go':
print('gogogo')
elif x == 'walk':
print('slow')
else:
print('stop now')
stop now
这个多行语句从if行扩展到else块。执行时,Python会执行第一次测试为真的语句下面的嵌套语句,或者如果所有测试都为假时,就执行else部分(在这个例子中,就是这样)。实际上,elif和else部分都可以省略,而且每一段中可以嵌套一个以上的语句。注意if、elif以及else结合在一起的原因在于它们垂直对齐,具有相同的缩进。
在Python,多路分支是写成一系列的if/elif测试(如上例所示),或者对字典进行索引运算或搜索列表。因为字典和列表可在运行时创建,有时会比硬编码的if逻辑更有灵活性。
>>> choice = 'ham'
>>> print({'spam':2.2,
'ham':1.2,
'eggs':0.9}[choice])
1.2
这个字典是多路分支:根据键的选择进行索引,再分支到一组值的其中一个,很像C语言的switch。
二者基本等效但前者比较冗长。这里字典键值如果再多会增加elif,为了举例未增加过多。Python if语句表达如下:
>>> if choice == 'spam':
print(2.2)
elif choice == 'eggs':
print(0.9)
else:
print(1.2)
1.2
>>>
注意:当没有键匹配时,这里if的else分句就按默认的情况处理。
字典默认值能编码到has_key测试、get方法调用或异常捕捉中。在这里也能用这些相同的技术,在字典式的多路分支中用于编写默认动作。如下是通过get方法处理默认值的情况。
>>> branch = {'spam':2.2,
'ham':1.2,
'eggs':0.9}
>>> print(branch.get('spam','Bad CHOICE'))
2.2
>>> print(branch.get('B','Bad CHOICE'))
Bad CHOICE
位于一条if语句中的in成员测试也有同样的默认效果:
>>> choice = 'bacon'
>>> if choice in branch:
print(branch[choice])
else:
print('Bad CHOICE')
Bad CHOICE
>>>
字典适用于将值和键相关联,但如果是通过if语句来编写的更复杂动作呢?
后续文章会讲到字典也可以包含函数,从而代表更为复杂的分支动作,并实现一般的跳跃表格。这类函数作为字典的值,通常写成函数名或lambda,通过增加括号调用来触发其动作。
虽然字典式多路分支在处理动态数据的程序中很有用,但多数程序员可能会发现,编写if语句是执行多路分支最直接的方式。编写代码时的原则是:有疑虑的时候,就遵循简易性原则和可读性原则。
真值测试
比较、相等以及真值,之前已经学过了,现在联系实际中的if语句来拓展下。
在Python中:
- 任何非零数字或非空对象都为真。
- 数字零、空对象以及特殊对象None都被认作是假。
- 比较和相等测试会递归地应用在数据结构中。
- 比较和相等测试会返回True或False
- 布尔and和or运算符会返回真或假的操作对象。
简而言之,布尔运算符是用于结合其他测试的结果。Python中有三种布尔表达式运算符:
X and Y
如果X和Y都为真,就是真。
X or Y
如果X或Y为真,就是真。
not X
如果X为假,那就是真(表达式返回True或False)。
X和Y可以是任何真值或者返回真值的表达式(例如,相等测试、范围比较等)。布尔运算符在Python中是字(不是C的&&、||和!)。
此外,布尔and和or运算符在Python中会返回真或假对象,而不是值True或False。
看下面的例子:
>>> 2 < 3 , 2 > 3
(True, False)
在Python中像这类值的比较会返回True或False作为其真值结果,但其实这些只是整数1和0的特殊版本。
另一方面,and和or运算符总会返回对象,不是运算符左侧的对象,就是右侧的对象。如果我们在if或其他语句中测试其结果,总会如预期的结果那样(每个对象本质上不是真就是假),但我们不会得到简单的True或False。
or测试:Python会由左至右求算操作对象,然后返回第一个为真的操作对象。再者,Python会在其找到的第一个真值操作数的地方停止。这通常叫做短路计算,因为求出结果后,就会使表达式其余部分短路(终止):
>>> 2 or 3, 3 or 2 #左为真则返回左,右为真则返回右
(2, 3) #否则 返回右边(true / false)
>>> [] or 3
3
>>> [] or {}
{}
第一行中,2和3两个操作数都是真(非零),所以Python总是在左边操作数停止并返回这个操作数。
另外两个测试中,左边的操作数为假(空对象),所以Python只会计算右边的操作数并将其返回(测试时,可能是真或假值)。
在结果知道时,and运算也会立刻停止。Python由左至右计算操作数,并且停在第一个为假的对象上:
>>> 2 and 3, 3 and 2 #左为假则返回左,左为真则返回右
(3, 2) #否则 返回右边(true / false)
>>> [] and {}
[]
>>> 3 and []
[]
>>>
这里第一行的两个操作数都是真,所以Python会计算两侧,并返回右侧的对象。
第二个,左侧的操作数为假([]),所以Python会在该处停止并将其返回作为测试结果。
最后,左边为真(3),所以Python会计算右边的对象并将其返回(碰巧是假的[])。
这些最终的结果都和C及其他多数语言相同:如果在if或while中测试时,会得到逻辑真或假的值。在Python中,布尔返回左边或右边的对象,而不是简单的整数标志位。
and和or这种行为,乍看之下似乎很难理解,看一看下文“为什么要在意布尔值”的例子,来了解它如何对Python程序员的代码编写产生好处的。
if/else三元表达式
Python中布尔运算符的一种常见角色就是写个表达式,像if语句那样执行。考虑下列语句,根据X的真值把A设成Y或Z。
就像这个例子所示,有时这类语句中涉及的元素相当简单,用四行代码编写似乎太浪费了。在其他时候,可能想将这种内容嵌套在较大的语句内,而不是将其结果赋值给变量。
Python引入了新的表达式格式,让我们可以在一个表达式中编写出相同的结果:
这个表达式和前边四行if语句的结果相同,但是更容易编写代码。就像这个语句的等效语句,只有当X为真,Python才会执行表达式Y,而只有当X为假,才会执行表达式Z。
这是短路(short-circuit)运算,就像布尔运算符一样的行为。以下是其工作的一些例子:
>>> A = 't' if 'spam' else 'f'
>>> A
't'
>>> A = 't' if '' else 'f'
>>> A
'f'
相同的效果可以小心地用and和or运算符的结合实现,因为它们不是返回左边的对象就是返回右边的对象:
这样行得通,但有个问题:得假定Y是布尔真值。如果是这样,效果就相同:and先执行,如果X为真,就返回Y;如果不是,就只返回Z。换句话说,我们得到的是"if X thenY else Z"。
如果需要这种表达式,就使用更易于记忆的Y if X else Z,或者如果组成的成份并不琐碎,就使用完整的if语句。
在Python中使用下列表达式也是类似的,因为bool函数会把X转换成对应的整数1或0,然后,就能用于从一个列表中挑选真假值:
例如
>>> ['f','t'][bool('spam')]
't'
>>> ['f','t'][bool('')]
'f'
然而,这并不完全相同,因为Python不会做短路运算,无论X值是什么,总是会执行Z和Y。这种应该少用,只有当组成成分都很简单时才用。
如果你想凸显你的技术,可以这么写,记得做好注释。
因为这种复杂性,最好还是使用更简单、更易懂的if/else表达式。最好写完整的if语句,让以后的修改能简单一些。
为什么要在意布尔值
使用Python布尔运算符有些不寻常行为的一种常见方式就是,通过or从一组对象中做选择。像这样的语句:
会把X设为A、B以及C之中第一个非空(为真)的对象,或者如果所有对象都为空,就设为None。这样行得通是因为or运算符会返回两对象之一,这成为Python中相当常见的编写代码的手法:从一个固定大小的集合中选择非空的对象(只要将其串在一个or表达式中即可)。
在更简单的形式中,这也通常用来指定一个默认值,下面的例子中,如果A为真(或非空)的话将X设置为A,否则,将X设置为default:
了解短路计算也很重要,因为布尔运算符右侧的表达式可能会调用函数来执行实质或重要的工作,不然,如果短路规则生效,附加的效果就不会发生。
在这里,如果f1返回真值(非空),Python将不再会执行f2。为了保证两个函数都会执行,要在or之前调用它们。
还有提到的另一种应用:基于布尔运作方式,表达式((A and B)or C)几乎可用来模拟if/else语句。
因为所有对象本质都是真或假,Python中,直接测试对象(if X:),而不是和空值比较(if X!='':),前者更为常见也更简单。就字符串而言,这两个测试是等效的。
预先设置的布尔值True和False与整数1和0是相同的,并且对于初始化变量(X=False)、循环测试(while True:)以及在交互提示模式中显示结果是很有用的。
对于运算符重载的讨论:当用类定义新的对象类型的时候,可以用__bool__或__len__方法指定其布尔特性。如果前者通过返回一个长度为0而成为空缺的并指定为假的对象的话(一个空的对象看做是假),将测试后者。
记住,在Python中和其他地方,简单一定比复杂更好。
确实是,有时候有些同事喜欢用一些高深的写法去写代码,目的是凸显本人技术?然而发生bug去修改遇到各种各样的问题,即便是他本人修改,修改的效率比不上简单写法。