On 6 May 2016 at 05:17, Kyle Lahnakoski <klahnakoski@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).
____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.