[Python-Dev] Avoid formatting an error message on attribute error

Victor Stinner victor.stinner at gmail.com
Wed Nov 6 23:32:33 CET 2013


Hi,

I'm trying to avoid unnecessary temporary Unicode strings when
possible (see issue #19512). While working on this, I saw that Python
likes preparing an user friendly message to explain why getting an
attribute failed. The problem is that in most cases, the caller
doesn't care of the message: the exception is simply deleted. For
example, hasattr() deletes immediatly the AttributeError.

It would be nice to only format the message on demand. The
AttributeError would keep a reference to the type. Keeping a strong
reference to the type might change the behaviour of some applications
in some corner cases. (Holding a reference to the object would be
worse, and the type looks to be preferred over the type to format the
error message.)

Pseudo-code for modified AssertionError:

    class AttributeError(Exception):
        def __init__(self, type, attr):
            self.type = type
            self.attr = attr
            self._message = None

        def __str__(self):
            if self._message is None:
                self._message = ("type object %s has no attribute %r"
                                 % (self.type.__name__, self.attr))
            return self._message

AttributeError.args would be (type, attr) instead of (message,).
ImportError was also modified to add a new "name "attribute".

If AttributeError cannot be modified (because of backward
compatibility), would it be possible to add a new exception inheriting
from AttributeError?


I have a similar project for OSError (generate the message on demand),
but it's more tricky because os.strerror(errno) depends on the current
locale...

***

Example of C code raising an AttributeError:

    PyErr_Format(PyExc_AttributeError,
                 "'%.50s' object has no attribute '%U'",
                 tp->tp_name, name);

Example of C code ignoring the AttributeError:

    value = _PyObject_GetAttrId(mod, &PyId___initializing__);
    if (value == NULL)
        PyErr_Clear();
    else {
        ...
    }

Example of Python code ignoring the AttributeError:

    try:
        get_subactions = action._get_subactions
    except AttributeError:
        pass
    else:
        ...

Another example in Python:

    try:
        retattr = getattr(self.socket, attr)
    except AttributeError:
        # the original error is not used
        raise AttributeError("%s instance has no attribute '%s'"
                             %(self.__class__.__name__, attr))

Victor


More information about the Python-Dev mailing list