Python学习4:流程控制

在 Python 中,流程控制语句包括条件语句(if-elif-else)、循环语句(for 和 while)、跳转语句(break、continue 和 return)和异常处理语句。

条件语句

条件语句用于在不同的条件下执行不同的代码块。Python 中的条件语句是 if-elif-else 结构。

# 条件语句示例
x = 10
if x < 0:
    print("x is negative")
elif x == 0:
    print("x is zero")
else:
    print("x is positive")

循环语句

循环语句用于重复执行一段代码,直到满足某个条件或达到某个条件次数为止。Python 中的循环语句包括 for 和 while 两种结构。

# for 循环示例
my_list = [1, 2, 3, 4, 5]
for item in my_list:
    print(item)

# while 循环示例
x = 10
while x > 0:
    print(x)
    x -= 1

遍历集合时修改集合的内容,会很容易生成错误的结果。因此不能直接进行循环,而是应遍历该集合的副本或创建新的集合:

# Create a sample collection
users = {'Hans': 'active', 'Éléonore': 'inactive', '景太郎': 'active'}

# Strategy:  Iterate over a copy
for user, status in users.copy().items():
    if status == 'inactive':
        del users[user]

# Strategy:  Create a new collection
active_users = {}
for user, status in users.items():
    if status == 'active':
        active_users[user] = status

跳转语句

跳转语句用于在循环或函数中跳过一些代码或终止循环。Python 中的跳转语句包括 break、continue 和 return。

# break 示例
my_list = [1, 2, 3, 4, 5]
for item in my_list:
    if item == 3:
        break
    print(item)

# continue 示例
my_list = [1, 2, 3, 4, 5]
for item in my_list:
    if item == 3:
        continue
    print(item)


# return 示例
def my_function(x):
    if x < 0:
        return None
    return x * 2

在这个示例中,我们使用 break 关键字来终止一个 for 循环,使用 continue 关键字来跳过一个循环迭代,使用 return 关键字来从函数中返回一个值。

pass 语句

pass 语句不执行任何操作。语法上需要一个语句,但程序不实际执行任何动作时,可以使用该语句。例如:

# pass 语句
while True:
    pass  # Busy-wait for keyboard interrupt (Ctrl+C)

def function():
    # to be implemented
    pass

class MyEmptyClass:
    pass

match 语句

match 语句接受一个表达式,并将其值与一个或多个 case 块中给定的模式进行比较。这在表面上类似于 C、Java 或 JavaScript(以及许多其他语言)中的 switch 语句,但它更类似于 Rust 或 Haskell 等语言中的模式匹配。只有第一个匹配的模式会被执行,并且它还可以从值中提取组件(序列元素或对象属性)到变量中。

最简单的形式是将一个目标值与一个或多个字面值进行比较:

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the internet"

注意最后一个代码块:“变量名” _ 被作为 通配符 并必定会匹配成功。 如果没有 case 语句匹配成功,则不会执行任何分支。

使用 | (“ or ”)在一个模式中可以组合多个字面值:

case 401 | 403 | 404:
    return "Not allowed"

模式的形式类似解包赋值,并可被用于绑定变量:

# point is an (x, y) tuple
match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"Y={y}")
    case (x, 0):
        print(f"X={x}")
    case (x, y):
        print(f"X={x}, Y={y}")
    case _:
        raise ValueError("Not a point")

请仔细研究此代码! 第一个模式有两个字面值,可以看作是上面所示字面值模式的扩展。但接下来的两个模式结合了一个字面值和一个变量,而变量 绑定 了一个来自目标的值(point)。第四个模式捕获了两个值,这使得它在概念上类似于解包赋值 (x, y) = point

如果使用类实现数据结构,可在类名后加一个类似于构造器的参数列表,这样做可以把属性放到变量里:

class Point:
    x: int
    y: int

def where_is(point):
    match point:
        case Point(x=0, y=0):
            print("Origin")
        case Point(x=0, y=y):
            print(f"Y={y}")
        case Point(x=x, y=0):
            print(f"X={x}")
        case Point():
            print("Somewhere else")
        case _:
            print("Not a point")

可在 dataclass 等支持属性排序的内置类中使用位置参数。还可在类中设置 __match_args__ 特殊属性为模式的属性定义指定位置。如果它被设为 (“x”, “y”),则以下模式均为等价的,并且都把 y 属性绑定到 var 变量:

Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)

读取模式的推荐方式是将它们看做是你会在赋值操作左侧放置的内容的扩展形式,以便理解各个变量将会被设置的值。 只有单独的名称(例如上面的 var)会被 match 语句所赋值。 带点号的名称 (例如 foo.bar)、属性名称(例如上面的 x=y=)或类名称(通过其后的 “(…)” 来识别,例如上面的 Point)都绝不会被赋值。

模式可以任意地嵌套。例如,如果有一个由点组成的短列表,则可使用如下方式进行匹配:

match points:
    case []:
        print("No points")
    case [Point(0, 0)]:
        print("The origin")
    case [Point(x, y)]:
        print(f"Single point {x}, {y}")
    case [Point(0, y1), Point(0, y2)]:
        print(f"Two on the Y axis at {y1}, {y2}")
    case _:
        print("Something else")

为模式添加成为守护项的 if 子句。如果守护项的值为假,则 match 继续匹配下一个 case 语句块。注意,值的捕获发生在守护项被求值之前:

match point:
    case Point(x, y) if x == y:
        print(f"Y=X at {x}")
    case Point(x, y):
        print(f"Not on the diagonal")

match 语句的其他特性:

  • 与解包赋值类似,元组和列表模式具有完全相同的含义,并且实际上能匹配任意序列。 但它们不能匹配迭代器或字符串。

  • 序列模式支持扩展解包操作:[x, y, *rest](x, y, *rest) 的作用类似于解包赋值。 在 * 之后的名称也可以为 _,因此,(x, y, *_) 可以匹配包含至少两个条目的序列,而不必绑定其余的条目。

  • 映射模式:{"bandwidth": b, "latency": l} 从字典中捕获 "bandwidth""latency" 的值。与序列模式不同,额外的键会被忽略。**rest 等解包操作也支持。但 **_ 是冗余的,不允许使用。

  • 使用 as 关键字可以捕获子模式:

    case (Point(x1, y1), Point(x2, y2) as p2): ...
    

    将把输入的第二个元素捕获为 p2 (只要输入是包含两个点的序列)

  • 大多数字面值是按相等性比较的,但是单例对象 True, FalseNone 则是按标识号比较的。

  • 模式可以使用命名常量。 这些命名常量必须为带点号的名称以防止它们被解读为捕获变量:

    from enum import Enum
    class Color(Enum):
        RED = 'red'
        GREEN = 'green'
        BLUE = 'blue'
    
    color = Color(input("Enter your choice of 'red', 'blue' or 'green': "))
    
    match color:
        case Color.RED:
            print("I see red!")
        case Color.GREEN:
            print("Grass is green")
        case Color.BLUE:
            print("I'm feeling the blues :(")
    

异常处理语句

异常处理语句:用于处理程序执行过程中可能出现的异常情况,Python 中的异常处理语句包括 try、except、finally 和 raise 语句。

try:
    x = int(input("Please enter a number: "))
    y = 10 / x
    print(y)
except ValueError:
    print("Invalid input")
except ZeroDivisionError:
    print("Cannot divide by zero")
else:
    print("No exception occurred")
finally:
    print("Execution completed")

# raise 语句
x = -1
if x < 0:
    raise ValueError("x must be non-negative")
Share this post:

Related content