[Python-Dev] Context management patterns (original) (raw)

Glenn Linderman v+python at g.nevcal.com
Sat Oct 19 12:47:45 CEST 2013


On 10/18/2013 11:38 PM, Nick Coghlan wrote:

However, that's a confusion about exception handling in general, not about the suppress context manager in particular. The same potential for conceptual confusion exists between:

for name in ("somefile.tmp", "someotherfile.tmp"): try: os.remove(name) except FileNotFoundError: pass and: try: for name in ("somefile.tmp", "someotherfile.tmp"): os.remove(name) except FileNotFoundError: pass At the syntactic level, when composing compound statements, the order of nestingalways matters. The with/for and for/with constructs are different, just as if/for and for/if are different. If a student makes it through an introductory Python course without learning that much, I'd have grave doubts about that course

Students that actually take courses might be OK... they might even read some of the documentation.

Indeed the problem can be produced with try/except syntax or with with/suppress. That has been obvious from the beginning of the discussion, and stated repeatedly. I suppose it is the "context management" connotation that with currently has, that makes me think that with/suppress is reasonably likely to get misused... in context management uses, one puts long blocks of code under with (not always, but often). In this particular case, that is a problem, yet not all the control flow examples would be limited to one line of code in the with block. So this is still a very special case, for a very small benefit, with an unusual limitation.

I have a new color of paint:

with pass_if( FileNotFoundError ): os_remove("somefile.tmp")

One thing about bikeshedding... after trying lots of colors, you might actually find one everyone likes. But if they aren't put out there to see, no one knows if they like it or not. And if there are a significant number of people that don't like the color, it either means the sun is in their eyes, or the color isn't the best, and that is sometimes hard to discern.

While I already realized that the with construct is really control flow, even the names that indicated that that have been suggested so far, even by me, didn't really capture the type of control flow. It hit me, reading your last message, that the key part is "pass"... it is an action (control flow), and it is the action that would be taken if written with try/except syntax. It isn't the exception, or the catching, that are the key.... it is the passing... passing over the with block because the exception happened. That even implies you don't want to pass much, certainly not a whole loop full of stuff, or a long string of statements.

Sadly, all the documentation that references "suppressing" an exception, is misleading. Misleading enough that you convinced yourself to rename from ignore to suppress after reading it, even though the two are nearly synonymous. The exceptions are not ignored, and the exceptions are not suppressed. They are handled by passing (which avoids the need for surrounding code to handle them, which is sort of like being ignored or suppressed, from the outside looking in... but pass describes the behavior for both inside and outside viewpoints!).

I believe your underlying concerns are actually with the non-local flow control possibilities that are inherent in a language that offers both exceptions and the ability to suppress them.

Are you referring to a different type of "suppress" than the one you just implemented? Where the language allows you to suppress an exception, and execution proceeds with the next statement? Where it would be more of a declarative style of suppression rather than an active "catch and pass". If so, it is more proof that "suppress" is the wrong term for your new feature.

Thanks again for sharing the big picture: you have before, but I see you've evolved it slightly. Delayed error handling I've had occasion to do, but not yet in Python. The constrained jump pattern is interesting, but the example is not complex enough to justify the syntax: the with solution is actually longer... if you initialized result they'd be the same length. The problem with the for/else construct is that the "not found" case falls through to the "found" case, which can be awkward, but that awkwardness isn't really demonstrated in the example. "exit_label" is an awkward name, too, since there are no labels, and no exit(). (yes, I know you meant exit the loop; naming is hard.)

I haven't yet wrapped my mind around all the possibilities of with creating an "empty" object, which gets populated by the various execution paths taken, but that combination does seem quite a bit more powerful than the simple with statement alone, which only sits at the front of a block. try/except/finally/else has lots of keywords and lots of places to put code :) Which doesn't always make the code clear, so abstractions using with may indeed be helpful... but care will have to be taken that the requirement for the added object and its manipulation doesn't get more cumbersome than straightforward coding of the problem without the abstraction.

-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20131019/f99b29aa/attachment.html>



More information about the Python-Dev mailing list