Python中的yield和raise关键字

一. yield — 生成器

基本概念:

yield 是 Python 中的一个关键字,它用于定义生成器。生成器是一种特殊类型的迭代器,它与常规函数的不同之处在于,生成器函数在执行时会“暂停”并返回一个值,之后可以恢复执行,直到再次遇到 yield

与普通函数不同,生成器在被调用时并不会立即执行代码。相反,它会返回一个生成器对象,这个对象可以用于逐个生成值,直到所有值都被生成完为止。

生成器函数:

生成器函数是通过 def 定义的普通函数,但它包含一个或多个 yield 表达式。当生成器函数被调用时,它不会立即执行,而是返回一个迭代器对象(即生成器)。调用该生成器的 __next__() 方法(可以通过 next() 函数调用)时,函数会开始执行,直到遇到 yield 语句时暂停,返回值给调用者,并保留当前函数的状态。

工作原理:
  1. 暂停与恢复:每次遇到 yield 时,函数的执行状态被“冻结”,函数返回 yield 后的值,直到下次调用 next() 时,函数从上次“冻结”的位置恢复执行。
  2. 一次生成一个值:生成器每次生成一个值,它并不会一次性返回所有的值。因此,生成器在处理大量数据时非常高效,因为它不会一次性将所有的值存储在内存中。
示例:
# 生成器函数:生成从1到最大值的数字
def count_up_to(max):
    count = 1
    while count <= max:
        yield count  # 每次暂停并返回当前的count
        count += 1

# 创建生成器对象
counter = count_up_to(3)

# 逐个获取生成的值
print(next(counter))  # 输出: 1
print(next(counter))  # 输出: 2
print(next(counter))  # 输出: 3
生成器的特点:
  • 节省内存:生成器一次只生成一个值,避免了在内存中存储所有值,适合处理大量数据。
  • 惰性求值:生成器是惰性计算的,它们直到需要时才生成下一个值。
  • 状态保存:每次执行到 yield 时,函数的执行状态都会被保存,下一次 next() 调用时会从上次的 yield 语句继续执行。
迭代器协议:

生成器实现了迭代器协议,即支持 __iter__()__next__() 方法,因此可以用 for 循环进行遍历:

for num in count_up_to(5):
    print(num)

这将逐个输出从 1 到 5 的数字。


二. raise — 异常抛出

基本概念:

raise 关键字用于在程序中主动抛出异常。它可以用来抛出标准异常,也可以抛出自定义的异常。使用 raise 可以让你显式地触发错误,或者将错误信息传递给上层调用者。它还可以与 try...except 块结合使用,用于重新抛出已捕获的异常。

抛出异常:

raise 后面可以跟一个异常类(如 ValueErrorTypeError 等)或者异常实例。你可以使用 raise 主动触发异常,在程序的错误处理部分或在输入数据无效时使用。

语法:
raise ExceptionType("Error message")
  • ExceptionType:是抛出的异常类型,可以是 Python 内建的异常(如 ValueError, TypeError, IndexError 等),也可以是自定义的异常类。
  • Error message:是一个可选的错误信息,用于描述异常的具体内容。
示例:
def divide(a, b):
    if b == 0:
        raise ZeroDivisionError("Cannot divide by zero!")  # 主动抛出异常
    return a / b

try:
    result = divide(10, 0)
except ZeroDivisionError as e:
    print(f"Error occurred: {e}")  # 捕获异常并处理

这段代码演示了如何使用 raise 触发一个 ZeroDivisionError 异常。

重新抛出异常:

当你在 try 块中捕获异常后,可能需要进一步处理或记录信息,也可能希望将该异常传递给调用者。在这种情况下,你可以使用 raise 重新抛出异常。

try:
    # 可能会抛出异常的代码
    raise ValueError("An error occurred")
except ValueError as e:
    print(f"Caught exception: {e}")
    raise  # 重新抛出异常

在这个例子中,捕获并处理了异常后,使用 raise 将异常重新抛出,可以让调用者在更高的层次上处理这个异常。

自定义异常:

你也可以自定义异常类,继承自 Exception 类,然后使用 raise 抛出自定义异常。

class CustomError(Exception):
    def __init__(self, message):
        super().__init__(message)

def do_something():
    raise CustomError("This is a custom error")

try:
    do_something()
except CustomError as e:
    print(f"Caught custom error: {e}")

这里,我们定义了一个 CustomError 类,它继承自 Exception。在 do_something() 函数中,我们使用 raise 抛出了一个自定义的异常。

raise 的应用场景:
  1. 输入验证:当输入数据不符合预期时,可以使用 raise 抛出异常,提示用户修正错误。
  2. 错误传播:在处理过程中遇到无法解决的错误时,使用 raise 重新抛出异常,交给上层逻辑来处理。
  3. 异常链:有时候你需要捕获某个异常并将其包装成不同类型的异常,以提供更多上下文信息或不同的错误处理方式。

总结:

  • yield

    • 使函数成为生成器,返回一个迭代器。
    • 节省内存,因为生成器按需生成结果,而不是一次性生成所有值。
    • 支持惰性求值,直到调用 next() 时才执行。
    • 常用于处理大量数据或者需要按需生成数据的场景。
  • raise

    • 用于主动抛出异常。
    • 可以触发标准异常或自定义异常,提供错误信息。
    • try...except 结合使用时,可以捕获、处理、或重新抛出异常,控制错误流转。

这两个关键字在 Python 中各自承担不同的角色,yield 主要用于迭代和数据流控制,而 raise 主要用于异常处理和错误控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值