
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/