try..yield..finally problem: a proposed solution.

Alan Kennedy alanmk at hotmail.com
Fri Jun 6 13:08:46 CEST 2003


Michael Sparks wrote:

> Taking your suggestion, you get a cleaned up version which is
> pretty elegant:
> 
> def finfunc():
>     try:
>         try:
>             # Risky code, e.g.
>             for i in xrange(10):
>                 t=i/random.randint(0,10)
>                 yield "data",i
>             raise Finality
>         except:
>             print "Finally"
>             raise
>     except Finality:
>         pass
> 
> for v in finfunc():
>     print v

[ Stuff elided ]

> But you [sometimes] get a 'exceptions must not be of 'NoneType' error.

Indeed, I discovered this during my prototyping, which is why I had the
structure that I did.

> If you use the original (form 3 for convenience):
> # Form 3
>     try:
>         yield
>     except Exception,x:
>         yield
>         raise x

But this isn't the original form, since there is no "finally" processing in it,
i.e. the second yield is only reached if there is an exception...

Adding in "finally" processing, this form is

    try:
        yield
        raise Finality
    except Exception, x:
        yield
        raise x

which does not clear or in any way "lose" the exception in the following code,
under Python 2.3a2. 

#------------------------------------------------------------------

import random

class Finality(Exception): pass

def finfunc():
    try:
        try:
            # Risky code, e.g.
            for i in range(10):
                x = 1/int(random.random()*10)
                yield x
            print "Successful processing"
            raise Finality
        except Exception, x:
            print "Finally"
            yield 42
            raise x
    except Finality:
        print "Finality discarded"
    except Exception, x:
        print "Told you that code was risky, didn't I?: %s" % str(x)

for v in finfunc():
    print v

#------------------------------------------------------------------

Incidentally, if you want to see the "exceptions cannot be Nonetype" exception
that Michael describes, then change the above definition of finfunc to remove
the explicit declaration of Exception, x: like so 

def finfunc():
    try:
        try:
            # Risky code, e.g.
            for i in range(10):
                x = 1/int(random.random()*10)
                yield x
            print "Successful processing"
            raise Finality
        except:             # <- this is different 
            print "Finally"
            yield 42
            raise           # <- and so is this
    except Finality:
        print "Finality discarded"
    except Exception, x:
        print "Told you that code was risky, didn't I?: %s" % str(x)

regards,

-- 
alan kennedy
-----------------------------------------------------
check http headers here: http://xhaus.com/headers
email alan:              http://xhaus.com/mailto/alan




More information about the Python-list mailing list