5.4.6 更复杂的条件
这就是你需要知道的有关if语句的全部知识。下面来说说条件本身,因为它们是有条件执行中最有趣的部分。
1. 比较运算符
在条件表达式中,最基本的运算符可能是比较运算符,它们用于执行比较。表5-1对比较运算符做了总结。
表5-1 Python比较运算符
表 达 式 描 述
x == y x 等于y
x
x > y x大于y
x >= y x大于或等于y
x
x != y x不等于y
x is y x和y是同一个对象
x is not y x和y是不同的对象
x in y x是容器(如序列) y的成员
x not in y x不是容器(如序列) y的成员
对不兼容的类型进行比较
从理论上说,可使用
将整数与字符串相加毫无意义,检查一个整数是否小于一个字符串也是一样。奇怪的是,在Python 3之前,竟然可以这样做。不过即便你使用的是较旧的Python版本,也应对这类比较敬而远之,因为结果是不确定的,每次执行程序时都可能不同。在Python 3中,已经不允
许这样比较不兼容的类型了。
与赋值一样, Python也支持链式比较:可同时使用多个比较运算符,如0
相等运算符
要确定两个对象是否相等,可使用比较运算符,用两个等号(==)表示。
>>> "foo" == "foo"
True
>>> "foo" == "bar"
False
两个等号?为何不像数学中那样使用一个等号呢?相信你很聪明,自己就能够明白其中的原因,但这里还是试试一个等号吧。
>>> "foo" = "foo"
SyntaxError: can't assign to literal
一个等号是赋值运算符,用于修改值,而进行比较时你可不想这样做。
is:相同运算符
这个运算符很有趣,其作用看似与==一样,但实际上并非如此。
>>> x = y = [1, 2, 3]
>>> z = [1, 2, 3]
>>> x == y
True
>>> x == z
True
>>> x is y
True
>>> x is z
False
在前几个示例中,看不出什么问题,但最后一个示例的结果很奇怪: x和z相等,但x is z的结果却为False。为何会这样呢?因为is检查两个对象是否相同(而不是相等)。变量x和y指向同一个列表,而z指向另一个列表(其中包含的值以及这些值的排列顺序都与前一个列表相同)。这两个列表虽然相等,但并非同一个对象。
这好像不可理喻?请看下面的示例:
>>> x = [1, 2, 3]
>>> y = [2, 4]
>>> x is not y
True
>>> del x[2]
>>> y[1] = 1
>>> y.reverse()
在这个示例中,我首先创建了两个不同的列表x和y。如你所见, x is not y(与x is y相反)的结果为True,这一点你早已知道。接下来,我稍微修改了这两个列表,现在它们虽然相等,但依然是两个不同的列表。
>>> x == y
True
>>> x is y
False
显然,这两个列表相等但不相同。
总之, ==用来检查两个对象是否相等,而is用来检查两个对象是否相同(是同一个对象)。
警告 不要将is用于数和字符串等不可变的基本值。鉴于Python在内部处理这些对象的方式,这样做的结果是不可预测的。
in:成员资格运算符
运算符in在2.2.5节介绍过,与其他比较运算符一样,它也可用于条件表达式中。
name = input('What is your name?')
if 's' in name:
print('Your name contains the letter "s".')
else:
print('Your name does not contain the letter "s".')
字符串和序列的比较
字符串是根据字符的字母排列顺序进行比较的。
>>> "alpha"
True
虽然基于的是字母排列顺序,但字母都是Unicode字符,它们是按码点排列的。
>>> " "
True
实际上,字符是根据顺序值排列的。要获悉字母的顺序值,可使用函数ord。这个函数的作用与函数chr相反:
>>> ord(" ")
128585
>>> ord(" ")
128586
>>> chr(128584)
' '
这种方法既合理又一致,但可能与你排序的方式相反。例如,涉及大写字母时,排列顺序就可能与你想要的不同。
>>> "a"
False
一个诀窍是忽略大小写。为此可使用字符串方法lower,如下所示(参见第3章):
>>> "a".lower()
True
>>> 'FnOrD'.lower() == 'Fnord'.lower()
True
其他序列的比较方式与此相同,但这些序列包含的元素可能不是字符,而是其他类型的值。
>>> [1, 2]
True
如果序列的元素为其他序列,将根据同样的规则对这些元素进行比较。
>>> [2, [1, 4]]
True
2. 布尔运算符
至此,你已见过很多返回真值的表达式(实际上,考虑到所有值都可解释为真值,因此所有的表达式都返回真值),但你可能需要检查多个条件。例如,假设你要编写一个程序,让它读取一个数,并检查这个数是否位于1~10(含)。为此,可像下面这样做:
number = int(input('Enter a number between 1 and 10: '))
if number
if number >= 1:
print('Great!')
else:
print('Wrong!')
else:
print('Wrong!')
这可行,但有点笨拙,因为你输入了print('Wrong!')两次。重复劳动可不是好事,那么该如何办呢?很简单。
number = int(input('Enter a number between 1 and 10: '))
if number = 1:
print('Great!')
else:
print('Wrong!')
注意 通过使用链式比较1
运算符and是一个布尔运算符。它接受两个真值,并在这两个值都为真时返回真,否则返回假。还有另外两个布尔运算符: or和not。通过使用这三个运算符,能以任何方式组合真值。
if ((cash > price) or customer_has_good_credit) and not out_of_stock:
give_goods()
短路逻辑和条件表达式
布尔运算符有个有趣的特征:只做必要的计算。例如,仅当x和y都为真时,表达式x andy才为真。因此如果x为假,这个表达式将立即返回假,而不关心y。实际上,如果x为假,这个表达式将返回x,否则返回y。 (这将提供预期的结果,你明白了其中的原理吗?)这种行为称为短路逻辑(或者延迟求值):布尔运算符常被称为逻辑运算符,如你所见,在有些情况下
将“绕过”第二个值。对于运算符or,情况亦如此。在表达式x or y中,如果x为真,就返回x,否则返回y。 (你明白这样做合理的原因吗?)请注意,这意味着位于布尔运算符后面的代码(如函数调用)可能根本不会执行。像下面这样的代码就利用了这种行为:
name = input('Please enter your name: ') or ''
如果没有输入名字,上述or表达式的结果将为''。在很多情况下,你都宁愿使用条件表达式,而不耍这样的短路花样。不过前面这样的语句确实有其用武之地。
5.4.7 断言
if语句有一个很有用的“亲戚”,其工作原理类似于下面的伪代码:
if not condition:
crash program
问题是,为何要编写类似于这样的代码呢?因为让程序在错误条件出现时立即崩溃胜过以后再崩溃。基本上,你可要求某些条件得到满足(如核实函数参数满足要求或为初始测试和调试提供帮助),为此可在语句中使用关键字assert。
>>> age = 10
>>> assert 0
>>> age = -1
>>> assert 0
Traceback (most recent call last):
File "", line 1, in ?
AssertionError
如果知道必须满足特定条件,程序才能正确地运行,可在程序中添加assert语句充当检查点,这很有帮助。
还可在条件后面添加一个字符串,对断言做出说明。
>>> age = -1
>>> assert 0
Traceback (most recent call last):
File "", line 1, in ?
AssertionError: The age must be realistic
领取专属 10元无门槛券
私享最新 技术干货