[Python-ideas] PEP-3151 pattern-matching

M.-A. Lemburg mal at egenix.com
Thu Apr 7 10:43:25 CEST 2011


Devin Jeanpierre wrote:
> Hello,
> 
> PEP-3151 < http://www.python.org/dev/peps/pep-3151/ > mentions a
> really weird syntax for pattern-matching. I was hoping I could suggest
> an alternative that's both more concise, and possible to implement
> without doing something drastic like changing existing syntax or
> semantics.
> 
> The PEP offers the pattern-matching syntax:
> 
>> except IOError as e if e.errno == errno.ENOENT: ...
> 
> I'd instead suggest something along the lines of
> 
>> except io_error(errno.ENOENT): ...
> 
> Implementing this is fairly straightforward, I've included it in the
> bottom of this email. Raising an exception becomes `raise
> io_error(errno.ENOENT)(msg)`. Some notational sugar can be implemented
> (for example, `raise io_error(errno.ENOENT, msg)` could also be made
> to work). I'm not fussed about the details.

The major difference between your proposal and the one in the
PEP is that in your case, an error object has to be created
or looked up via a function call regardless of whether the
case matches or not.

You typically don't want that to happen in tight loops and
except-clauses are designed to be cheap if they don't match.

> I personally prefer keeping the errnos as a big part of handling
> exceptions, they're common across OSes and involve less research /
> memorization for those that are already aware of errno. I guess what
> I'd like to see is the same exception hierarchy proposed by the PEP,
> but with the addition of allowing errnos to be specified by
> pattern-matching, so that errors not covered by the hierarchy, or more
> specific than the hierarchy, can be concisely caught. However, I'm not
> really well-versed in the pros and cons for all of this.

The main problem with the PEP is the proposal to flatten existing
exception class hierarchies, e.g. making socket.error the same
as IOError.

This introduces very subtle compatibility problems with code that
uses the flattened exception classes in separate except branches, e.g.

try:
 ...
except socket.error:
 ...
except IOError:
 ...

With the PEP implemented, the above code would never get
to execute the IOError branch and instead divert all error
handling to the socket.error branch which may well not be
aware of all the extra cases it now has to handle.

I think that this part of the PEP should not be accepted.

The addition of new IOError subclasses for common errno cases
is useful.

It would be even more useful, if there were a way to catch
standard IOErrors with those errnos using those same classes,
so that the following becomes possible:

try:
 ...
 raise IOError(errno.EPERM, "permission denied")
except PermissionError:
 ...

and works as one would expect, that is, catch the EPERM error.

Without such support, you'd still have to write:

try:
 ...
 raise IOError(errno.EPERM, "permission denied")
except PermissionError:
 ...EPERM handling code...
except IOError as error:
 if error.errno == errno.EPERM:
   ...EPERM handling code...

duplicating the error handling code.

Perhaps the IOError constructor could be made to switch
the class of the generated object based on the errno
attribute passed to the constructor.

That way no new syntax would be necessary at all.

> Above all, I'd like for the pattern matching alternative to be a bit
> more reasonable. It doesn't have to be verbose and it doesn't have to
> involve new syntax. Apologies for any mistakes in the code, they are
> my own.
> 
> Here's the code:
> 
> 
> # evil global state or something
> error_classes = {}
> 
> def io_error(errno_, msg=None): # or something, you get the idea
>     try:
>         cls = error_classes[errno_]
>     except LookupError:
>         class IOErrorWithErrno(IOError):
>             errno = errno_
> 
>         cls = error_classes[errno_] = IOErrorWithErrno
> 
>     return error_classes[errno_]
> 
> 
> # example of usage
> import errno
> try:
>     raise io_error(errno.ENOENT)("<Error message>")
> except io_error(errno.ENOENT):
>     print("success")
> 
> 
> Thanks for your time!
> Devin Jeanpierre

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Apr 07 2011)
>>> Python/Zope Consulting and Support ...        http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
________________________________________________________________________

::: Try our new mxODBC.Connect Python Database Interface for free ! ::::


   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
           Registered at Amtsgericht Duesseldorf: HRB 46611
               http://www.egenix.com/company/contact/



More information about the Python-ideas mailing list