[Python-ideas] Block-Scoped Exception Handlers

Kyle Lahnakoski klahnakoski at mozilla.com
Fri May 6 10:50:30 EDT 2016


On 5/5/2016 10:17 PM, Nick Coghlan wrote:
> On 6 May 2016 at 05:17, Kyle Lahnakoski <klahnakoski at mozilla.com> wrote:
>> May you provide me with an example of how contextmanager would help with
>> the indentation?
> contextmanager doesn't, ExitStack does (which is in the standard
> library for 3.3+, and available via contextlib2 for earlier versions).

Thank you for the examples, and they do reduce indention when you have
callbacks defined, or dealing with resources.  This does not seem to
help in the case of exception handlers.   Exception handlers have access
to block scope variables, and have code blocks that do not require a `def`.

I should have added different types of exception handlers to my initial
email to distract from the chaining exception.   Consider the exception
handler that simply stops trying to process the todo items:

|____def process_todo(todo): |||____||||____|pre_process() ||||____||||||____||||||||for t in todo: |||||____||||||________exc|||||||||||||||||||||||ept Exception, e: |||||_||||||___||||||||_||||||___||||||||_||||||___||||||||_||||||___|||break|
||||_||||||___||||||||_||||||___||||||||_||||||___|||process(t) |||||_||||||___||||||||_||||||___|||post_process() As an alternative to ||____def process_todo(todo): |||____||||____|pre_process() ||||____||||||____||||||||for t in todo: |||||____________try ||||||||||||_____||||||___||||||||_||||||___||||||||_||||||___|||process(t)
|____||||||________exc|||||||||||||||||||||||ept Exception, e: |||||_||||||___||||||||_||||||___||||||||_||||||___||||||||_||||||___|||break|
||||_||||||___||||||||_||||||___|||post_process() |

Of course, a couple `try` nested statements make the indentation worse. 
For example, we wish to ignore problems in dealing with todo items, like
above, but the todo items are complicated; each is a dict() of details. 
Failure to deal with one of the details is ignored, but the rest of the
details are still attempted:

|def process_todo(todo): ____pre_process() ____for t in todo:
________except Exception, e: ____________break ________for u, v in
t.items(): ____________except Exception, e: ________________continue
____________process() ____post_process() Which is better than what I do
now: def process_todo(todo): ____pre_process() ____for t in todo:
________try: ____________for u, v in t.items(): ________________try:
____________________process() ________________except Exception, e:
____________________continue ________except Exception, e:
____________break ____post_process() |


|I have not touched on more complicated except clauses; ones that have
multiple lines, and ones that use, or update block-scoped variables.

ExitStack is good for manipulating `with` clauses as first order
objects, but they are limited to what you can do with `with` statements:
Limited to naive exception handling, or simple chaining.   If was to use
ExitStack in the example above (using `continue` and `exit`), maybe I
would write something like:

def process_todo(todo):
____with ExitStack() as stack:
________pre_process()
________for t in todo:
____________stack.enter_context(BreakOnException())
____________for u, v in t.items():
________________stack.enter_context(ContinueOnException())
________________process()
________________stack.pop()  # DOES THIS EXIST?  IT SHOULD
________post_process()  

|

|This terrible piece of (not working) code assumes it is even possible
to write a `BreakOnException` and `ContinueOnException`. It also
requires a `pop` method, which is not documented, but really should
exist.  Without a `pop` method, I would need another ExitStack instance,
and a `with` statement to hold it.|

||

||

|I hope I have convinced you that ExitStack, and `with` block magic,
does a poor job of covering the use cases for `try` statements.  Maybe I
should make examples that use the loop variables in the `except` clause
for more examples?|

||

|At a high level:  The `try/except/finally` is powerful structure. 
Realizing that the `try/finally` pair is very common leads to the
creation of `with`. I am proposing the same logic for `try/catch` pair: 
They are commonly paired together and should have an optimized syntax. |

||||

||

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20160506/a83f210f/attachment-0001.html>


More information about the Python-ideas mailing list