【问题标题】:Raising exception in a generator, handle it elsewhere and vice versa in python在生成器中引发异常,在其他地方处理它,反之亦然在 python
【发布时间】:2026-01-14 23:10:02
【问题描述】:

我正在向更高级的方向思考,也很难找到解决这个问题的方法。在做出任何决定之前,我想征求专家的意见来解决这个问题。

增强的生成器具有新方法 .send() 和 .throw(),它们允许调用者传递消息或引发异常进入生成器(协程)。

来自 python 文档:这非常方便,尤其是 .throw() 方法,它请求生成器处理调用者中引发的异常。

请求 #1:上述语句的任何示例代码。我没有找到任何代码sn-ps来解释这个。

但是,我也在考虑相反的问题:生成器能否引发异常,将其传递给调用者,让调用者“修复”它,然后继续生成器自己的执行?这就是我所说的“反向投掷”。

请求#2:上述语句的任何示例代码。我没有找到任何代码sn-ps来解释这个。

仅仅在生成器中引发异常是不行的。我在生成器中尝试了“raise SomeException”,但没有奏效,因为在“raise”之后,生成器无法再执行——它只是停止,进一步尝试运行生成器会导致 StopIteration 异常。换句话说,“raise”比“yield”要致命得多:一个人可以在屈服于调用者后恢复自己,但“raise”会将自己送入死胡同。

我想知道是否有简单的方法可以在 Python 中进行“反向抛出”?这将使我们能够编写通过相互抛出异常来进行协作的协程。但是为什么要使用异常呢?嗯,我不知道……这一切都是从一个粗略的想法开始的。

案例研究代码:

class MyException(Exception):pass


def handleError(func):
''' handle an error'''
    errors =[]
    def wrapper(arg1):
        result = func(arg1)

        for err in findError(result):
            errors.append(err)

        print errors
        return result

    return wrapper

def findError(result):
'''
Find an error if any
'''
    print result
    for k, v in result.iteritems():
        error_nr = v % 2
        if error_nr ==0:
            pass
        elif error_nr > 0:
            yield MyException

@handleError
def numGen(input):

''' This function take the input and generates 10 random numbers. 10 random numbers are saved in result dictionary with indices. Find error decorator is called based on the result dictionary'''

    from random import randint
    result= {}
    errors = []
    for i in range(9):
        j = (randint(0,4))
        result[i] = input + j
    return result

if __name__ == '__main__':
    numGen(4)

任何人都可以根据案例研究示例解释这两个想法(在生成器中引发异常并在其他地方处理,反之亦然)?我确实希望这两种方法各有利弊。

提前致谢。

从可靠和/或官方来源寻找答案。

【问题讨论】:

    标签: python exception generator yield


    【解决方案1】:

    请求 #1(.throw() 的示例)

    我从未真正使用过它,但您可以在事后使用它来改变生成器中的行为。当然,您也可以使用.send 执行此操作,但是您需要使用yield 表达式(可能位于代码中的多个位置)来处理它,而不是通过尝试集中处理-除了块。

    def getstuff():
        i=0
        try:
            while True:
                yield i
                i+=1
        except ValueError:
            while True:
                yield i**2
                i+=1
    
    generator = getstuff()
    
    print("Get some numbers...")
    print(next(generator))
    print(next(generator))
    print(next(generator))
    
    print("Oh, actually, I want squares!")
    print(generator.throw(ValueError))
    print(next(generator))
    print(next(generator))
    

    【讨论】:

      【解决方案2】:

      请求#1:上述语句的任何示例代码。我没有找到任何代码sn-ps来解释这个。

      看看ayscio源码

      https://github.com/python/asyncio/search?utf8=%E2%9C%93&q=.throw

      请求#2:上述语句的任何示例代码。我没有找到任何代码sn-ps来解释这个。

      今天在 python 中没有办法* - 也许(如果证明有用)可能是一个很好的增强

      *也就是说,您可以使用 yield 来指示框架在其他地方引发异常..

      【讨论】:

        【解决方案3】:

        我需要解决这个问题几次,并在搜索其他人做了什么后发现了这个问题。我认为我不会使用 OP 建议的任何一种方法——它们非常复杂。

        一个选项 - 可能需要稍微重构一些东西 - 将简单地 throw 生成器中的异常(到另一个错误处理生成器)而不是 raise 它。这可能是这样的:

        def f(handler):
            # the handler argument fixes errors/problems separately
            while something():
                try:
                    yield something_else()
                except Exception as e:
                    handler.throw(e)
            handler.close()
        
        def err_handler():
            # a generator for processing errors
            while True:
                try:
                    yield
                except Exception1:
                    handle_exc1()
                except Exception2:
                    handle_exc2()
                except Exception3:
                    handle_exc3()
                except Exception:
                    raise
        
        def process():
            handler = err_handler()
            for item in f(handler):
                do stuff
        

        这并不总是最好的解决方案,但它肯定是一种选择,而且相对容易理解。

        【讨论】:

          最近更新 更多