Raising exception in a generator, handle it elsewhere and vice versa in python
Question: I'm thinking in a direction more advanced as well as difficult to find
solutions this problem. Before coming to any decision, I thought of asking
expert advice to address this problem.

The enhanced generators have new methods .send() and .throw() that allow the
caller to pass messages or to raise exceptions _into_ the generator
(coroutine).

From python documentation: This can be very handy, especially the .throw()
method that requests the generator to handle exceptions raised in the caller.

**Request #1: Any example code for the above statement. I didn't find any code
snippets for this explanation.**

However, I'm considering the inverse problem as well: can a generator raise an
exception, pass it to the caller, let the caller "repair" it, and continue the
generator's own execution? That is what I would like to call a "reverse
throw".

**Request #2: Any example code for the above statement. I didn't find any code
snippets for this explanation.**

Simply raising exceptions in the generator is not OK. I tried "raise
SomeException" in the generator, and that didn't work, because after a "raise"
the generator can no longer be executed --- it simply stops, and further
attempts to run the generator cause the StopIteration exception. In other
words, "raise" is much more deadly than "yield": one can resume itself after
yielding to the caller but a "raise" sends itself to the dead end.

I wonder if there are simple ways to do the "reverse throw" in Python? That
will enable us to write coroutines that cooperate by throwing exceptions at
each other. But why use exceptions? Well, I dunno... it all began as some
rough idea.

CASE STUDY CODE:

    
    
    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)
    

Could anyone explain please both the ideas based on case study example(Raising
exception in a generator and handle it elsewhere vice versa)? I do expect
pro's and con's of both methods.

Thanks in advance.

Looking for an answer drawing from credible and/or official sources.


Answer: # Request #1 (Example for .throw())

I have never actually used this, but you _could_ use it to change behaviour in
the generator after the fact. You can also do this with `.send` of course, but
then you'll need to deal with it in the line with the `yield` expressions
(which might be in several locations in the code), rather than centralized
with a try-except block.

    
    
    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))
    

