[Python-Dev] On suppress()'s trail blazing (was Re: cpython: Rename contextlib.ignored() to contextlib.ignore())

Terry Reedy tjreedy at udel.edu
Thu Oct 17 22:03:31 CEST 2013


On 10/17/2013 12:06 PM, Barry Warsaw wrote:
> On Oct 18, 2013, at 01:26 AM, Nick Coghlan wrote:
>
>> By contrast, suppress() and redirect_stdout() are the *first* general
>> purpose context managers added to contextlib since its incarnation in
>> Python 2.5 (although there have been many various domain specific
>> context manager additions elsewhere in the standard library).
>
> There's a fundamental conceptual shift here that's worth exploring more,

I noticed the same thing upon reading that. With statements are a 
general special-purpose tool.

> and which I think was first identified by RDM.

I missed this at the time.

> Until now, context managers were at their heart (at least IMHO) about managing
> "resources".
...

> We need only look at the typical @contextmanager use to see the idiom they
> embody.  As shown in the docstring:
>
> @contextmanager
> def acquire():
>      resource = get_some_resource()
>      try:
>          yield # execute the operation
>      finally:
>          # No matter what happened above...
>          resource.free()
>
> redirect_stdout() conforms to this fine tradition, with the resource being
> sys.stdout.

 From the with statement doc, second sentence: "This allows common 
try...except...finally usage patterns to be encapsulated for convenient 
reuse."

> suppress() breaks the mold, which I think is what is breaking people's
> brains.  It isn't about guaranteeing that a resource is restored to its
> original value after some operation.  It's about short circuiting that
> operation.

A suppress() is, in a sense, an empty cm as its only effect is to 
exploit the following: "If the suite was exited due to an exception, and 
the return value from the __exit__() method was false, the exception is 
reraised. If the return value was true, the exception is suppressed, and 
execution continues with the statement following the with statement."

This is clear with a direct implementation instead of the magical 
indirect one that Nick used (with @contextmanager and a generator 
function). I believe the following is equivalent, and one line shorter.

class suppress:
   def __init__(self, *exceptions):
     self.exceptions = exceptions
   def __exit__(self, etype, eval, etrace):
     return etype in self.exceptions

One might consider this an abuse, like comprehensions written purely for 
their side effect.

> Just look at the implementation to see this shift in perspective.  It doesn't
> use try/finally, it uses try/except.
>
> So it's important to acknowledge that suppress() is charting new territory and
> it will take some exploration and experimentation to get used to, or maybe
> even to decide whether it's a good idea.  It'll be interesting to see whether
> this fundamental difference is easily explained, understood, and internalized
> and that will go a long way to figuring out whether this is a good idea to be
> expanded on in the future.

-- 
Terry Jan Reedy



More information about the Python-Dev mailing list