[Python-Dev] Exceptions *must*? be old-style classes?

Armin Rigo arigo at tunes.org
Mon Jan 17 11:52:19 CET 2005


Hi,

On Fri, Jan 14, 2005 at 07:20:31PM -0500, Jim Jewett wrote:
> The base of the Exception hierarchy happens to be a classic class.
> But why are they "required" to be classic?

For reference, PyPy doesn't have old-style classes at all so far, so we had to
come up with something about exceptions.  After some feedback from python-dev
it appears that the following scheme works reasonably well.  Actually it's
surprizing how little problems we actually encountered by removing the
old-/new-style distinction (particularly when compared with the extremely
obscure workarounds we had to go through in PyPy itself, e.g. precisely
because we wanted exceptions that are member of some (new-style) class
hierarchy).

Because a bit of Python code tells more than long and verbose explanations,
here it is:

def app_normalize_exception(etype, value, tb):
    """Normalize an (exc_type, exc_value) pair:
    exc_value will be an exception instance and exc_type its class.
    """
    # mistakes here usually show up as infinite recursion, which is fun.
    while isinstance(etype, tuple):
        etype = etype[0]
    if isinstance(etype, type):
        if not isinstance(value, etype):
            if value is None:
                # raise Type: we assume we have to instantiate Type
                value = etype()
            elif isinstance(value, tuple):
                # raise Type, Tuple: assume Tuple contains the constructor
                #                    args
                value = etype(*value)
            else:
                # raise Type, X: assume X is the constructor argument
                value = etype(value)
        # raise Type, Instance: let etype be the exact type of value
        etype = value.__class__
    elif type(etype) is str:
        # XXX warn -- deprecated
        if value is not None and type(value) is not str:
            raise TypeError("string exceptions can only have a string value")
    else:
        # raise X: we assume that X is an already-built instance
        if value is not None:
            raise TypeError("instance exception may not have a separate"
                            " value")
        value = etype
        etype = value.__class__
        # for the sake of language consistency we should not allow
        # things like 'raise 1', but it's probably fine (i.e.
        # not ambiguous) to allow them in the explicit form 'raise int, 1'
        if not hasattr(value, '__dict__') and not hasattr(value, '__slots__'):
            raise TypeError("raising built-in objects can be ambiguous, "
                            "use 'raise type, value' instead")
    return etype, value, tb


Armin


More information about the Python-Dev mailing list