条件控制
Python 中的条件控制只有if
一种,其语句格式为:
if 条件1:
语句块1
elif 条件2:
语句块2
else:
语句块3
一个if
语句中,可以有多个elif
条件语句块,但是仅有一个else
语句块。if
语句可以嵌套在其他语句块结构中,但是要注意语句块的缩进。
这里需要注意以下两个使用要点:
- 每个条件后面都要使用冒号
:
,表示接下来是满足条件后要执行的语句块。冒号也是定义新语句块的符号。 - 一个语句块中的语句要使用相同的缩进。
在 Python 中,if
语句的使用方法十分灵活。由于 Python 没有其他语言中的三元操作符,即?:
操作,但是 Python 利用if
语句实现了更加强大的选择赋值操作。这种操作与前面提到过的列表推导式十分相似,以下用一个示例来说明。
c = []
b = max(c) if len(c) > 0 else -1
在上例中,if
被放在了一个表达式后面,这表示这个表达式的执行将由if
条件来决定,如果条件不满足,则返回else
语句的值。所以上例中b
的值即为-1
。如果列表c
中有内容,不是空列表,则b
的内容则是列表中的最大值。
关于 switch
从前面的基本控制语句中可以看出,Python 中没有提供 switch/case 语句。这是因为 Python 认为 switch/case 语法结构需要对参与判断的内容进行 Hash 和唯一性识别,与 Python 的优雅背道而驰。但实际上,我们依旧有多种方法来实现 switch/case 语法结构的替代。
最常用的替代方法是使用字典。
def case(value):
return {
'value1': some_value,
'value2': lambda x: x + 1
}.get(value, None)
case(some_value)
使用字典来实现 switch/case 结构依靠字典的键来进行判断,返回的是字典中键对应的值。另外一种替代方法则用到了后文中才会提到的一些技术,例如嵌套函数和生成器。
def switch(value):
fall = False
def match(\*args):
nonlocal value, fall
if fall or not args:
return True
elif value in args:
fall = True
return True
else:
return False
yield match
for case in switch('v'):
if case('v'):
pass
if case('b'):
pass
这种替代方法使用生成器,返回了用于判断的函数,实现了 switch/case 的连续判断分支结构。在这种方法中,对于match()
中的逻辑可以根据需要进行更加详细的定义。
match
结构
在Python 3.10版本中,一个功能更加强大的match
语句结构被引入了进来。自此,Python中也就具备了类似与switch
语句的结构,但是功能要更加强大。
match
语句格式非常简单,其使用格式如下所示。
match 表达式:
case 条件1:
语句1
case 条件2:
语句2
case 条件3 | 条件4 | 条件5:
语句3
case default:
默认语句
match
语句最简单的使用方式就是跟其他语言中的switch
语句一样,在case
语句中列举需要匹配的值即可。此时的match
语句相当于多条if exp == value:
的组合。如果想要达到在匹配多个值时都执行相同分支语句的效果,那么可以使用上面格式说明中的组合条件:case 条件 | 条件 | 条件:
,这种形式的分支允许match
语句匹配列举的任意条件。
传统使用if/else
结构分支语句的时候,在语句结构的最后往往会使用一个else
语句块来执行没有任何匹配内容时的处理。在match
语句中,这种默认匹配是采用case default:
或者使用case _:
的分支来声明的,这个默认分支通常都被放置在整个match
语句结构的末尾。
match
语句还支持对给定的表达式进行解构,例如以下示例中就解构了一个元组。
point = (2, 1)
match point:
case (1, y):
print(f"点在行1,列{y}上")
case (x, 0):
print(f"点在纵座标轴上,行{x}")
case (x, y):
print(f"点在行{x},列{y}上")
case _:
raise ValueError("给定值不是一个点坐标。")
除了可以解构元组以外,match
语句还可以解构数据类,其解构的使用方法与解构元组基本一致,只是case
分支要改用数据类的类名来进行解构操作指定,如果只需要解构其中一部分内容,还可以使用命名参数来获取指定字段的内容。
另外,对于上面这个示例来说,还可以使用更加Pythonic的方式,那就是使用if
来执行额外的判断。改写一下上面这个示例变成了以下的样子。
point = (2, 1)
match point:
case (x, y) if x == 1:
print(f"点在行1,列{y}上")
case (x, y) if y == 0:
print(f"点在纵座标轴上,行{x}")
case (x, y):
print(f"点在行{x},列{y}上")
case _:
raise ValueError("给定值不是一个点坐标。")
在使用if
进行额外判断的时候,要记住,match
语句会首先捕获值,然后再执行if
判断。
对于匹配枚举类中的成员,匹配的值必须书写连带枚举类名称的枚举成员全称,例如以下示例。
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
match color:
case Color.RED:
pass
case Color.GREEN:
pass
case Color.BLUE:
pass
在对枚举类成员进行匹配的时候,match
语句中的分支应该尽量列举枚举中所有可能的值,避免出现空缺匹配的问题。