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

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 redirectstdout() 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 = getsomeresource() try: yield # execute the operation finally: # No matter what happened above... resource.free() redirectstdout() 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