try..yield..finally problem: a proposed solution.
michaels at rd.bbc.co.uk
Fri Jun 6 12:30:45 CEST 2003
Taking your suggestion, you get a cleaned up version which is
# Risky code, e.g.
for i in xrange(10):
for v in finfunc():
However, you find that *if* your code is of the form:
# Form 1
and not of the form:
# Form 2
yield ### You're going to hate this...
raise ### Line A
Then you find this works suggestion works fine, for all exceptions - those
deriving from the Exception class, or otherwise. If you use form 2 however
it breaks horribly.
If you use the original (form 3 for convenience):
# Form 3
Then this always works... for exceptions deriving from the Exception
class. (and breaks with any legacy code)
If you use form 2, when you yield, the "current exception" is cleared.
ie when you do the raise on Line A you get a 'exceptions must not be of
NoneType' error. Clearly whereever this current exception is stored, it
either isn't in the python stack frame that's put aside when you yield,
or it's explicitly cleared. This strikes me as either a bug, or an
undocumented "boundary feature".
Minimal test case:
for v in finfunc():
However, in Form 3, we catch and bind the exception to x, so that despite
the current exception being cleared we can still rethrow, but of course
you lose the benefits of the stack trace pointing at the right place...
Form 3 however has the disadvantage that because it doesn't catch all
exceptions, it means that you don't have the same try...finally semantics
that have with Form 1. (Some exceptions - even if they're not stylistically
nice - can still get through and cause breakage.)
Having played with this for a few days, and reading the discussion I think
that the decision to disallow:
Is a good one - it results in too great a likelyhood of people shooting
themselves in the foot.
However the cleanest alternative:
Suffers from the downside that if you yield inside the except clause that
the current exception is cleared. (Which strikes me as a bug, since you'd
expect the runtime state in the generator not to changed after a yield.
Also I'd view it as a bug since otherwise I can write the code looking
cleaner in C ;)
Form 1 is the nicest from many perspectives, but Form 3 always works. I'm not
sure of the best way of resolving this, or whether to just use my original
non-try-finally versions instead now :-)
Michael.Sparks at rd.bbc.co.uk
British Broadcasting Corporation, Research and Development
Kingswood Warren, Surrey KT20 6NP
This message (and any attachments) may contain personal views
which are not the views of the BBC unless specifically stated.
More information about the Python-list