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

Steven D'Aprano steve at pearwood.info
Thu Nov 7 01:20:31 CET 2013


On Wed, Nov 06, 2013 at 11:32:33PM +0100, Victor Stinner wrote:
> 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.

My initial instinct here was to say that sounded like premature 
optimization, but to my surprise the overhead of generating the error 
message is actually significant -- at least from pure Python 3.3 code.

That is, the time it takes to generate the message:

"'%s' object has no attribute %r" % (obj.__class__.__name__, attrname)

is about the same as the time to raise and catch an exception:

try:
    raise AttributeError
except AttributeError:
    pass

(measured with timeit).


Given that, I wonder whether it would be worth coming up with a more 
general solution to the question of lazily generating error messages 
rather than changing AttributeError specifically. Just thinking aloud -- 
perhaps this should go to python-ideas? -- maybe something like this:

class _LazyMsg:
    def __init__(self, template, obj, attrname):
        self.template = template
        self.typename = type(obj).__name__
        self.attrname = attrname
    def __str__(self):
        return self.template % (self.typename, self.attrname)

Then:

py> err = AttributeError(
...     _LazyMsg("'%s' object has no attribute '%s'", None, "spam"))
py> raise err
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'spam'


Giving the same effect from C code, I leave as an exercise for the 
reader :-)


> It would be nice to only format the message on demand. The
> AttributeError would keep a reference to the type. 

Since only the type name is used, why keep a reference to the type 
instead of just type.__name__?


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

I don't like changing the signature of AttributeError. I've got code 
that raises AttributeError explicitly.



-- 
Steven


More information about the Python-Dev mailing list