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

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to