You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为可迭代对象添加异常处理装饰器?寻求更优Python实现

更简洁的Pythonic实现方案

你可以用一个统一的包装器处理两类函数,无需单独判断是否为生成器函数。核心思路是:先捕获函数调用阶段的异常,再通过yield from统一处理迭代过程中的异常——不管原函数返回的是列表还是生成器/迭代器,yield from都能遍历其元素,同时捕获迭代时的异常。

from functools import wraps

def failing_generator():
    for i in range(1, 5):
        if i % 2 == 0:
            print('I dont like even numbers.')
            raise ValueError(i)
        yield i

def bad_list():
    lst = []
    for i in range(1, 5):
        if i % 2 == 0:
            raise ValueError(i)
        lst.append(i)
    return lst

def catch_iter_exceptions(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        # 捕获函数调用时的异常(比如返回列表的函数构建列表时抛出的异常)
        try:
            iterable = fn(*args, **kwargs)
        except ValueError as err:
            print('Not to worry.')
            return
        
        # 捕获迭代过程中的异常(生成器/迭代器遍历阶段的异常)
        try:
            yield from iterable
        except ValueError as err:
            print('Not to worry.')
    
    return wrapper

# 测试生成器函数
print("测试生成器函数:")
for x in catch_iter_exceptions(failing_generator)():
    print(x)

# 测试返回列表的函数
print("\n测试返回列表的函数:")
for x in catch_iter_exceptions(bad_list)():
    print(x)

运行结果

测试生成器函数:
1
I dont like even numbers.
Not to worry.

测试返回列表的函数:
Not to worry.

方案优势

  1. 代码更简洁:无需借助isgeneratorfunction判断函数类型,一个包装器统一处理两类场景。
  2. 符合Python风格:利用yield from的特性,自然遍历任何可迭代对象,同时统一捕获迭代阶段的异常。
  3. 兼容性强:不管原函数返回列表、生成器还是其他迭代器(比如iter()创建的迭代器),都能正确捕获异常。

如果需要保持原函数的返回类型(比如原函数返回列表,包装后也返回列表而非生成器),可以在迭代完成后将元素收集为列表返回,但这样会失去迭代器的惰性特性。如果你的场景允许返回生成器(毕竟都是可迭代对象),上面的方案是最优选择。

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:50:35