[Python-Dev] OT: Performance vs. Clarity vs. Convention

Guido van Rossum guido@python.org
Wed, 05 Jun 2002 21:07:11 -0400

> class Comment:
>     def __init__(self, content=''):
>         self.content = content
>     def __call__(self, content=''):
>         o = self.__class__(content)
>         return str(o)
>     def __str__(self):
>         return '<!-- %s -->' % self.content
>     def __repr__(self):
>         return repr(self.__str__())
> When I look at this, I see certain decisions I've made and I'm wondering if
> I've made the best decisions. I'm wondering how to balance performance
> against clarity and proper coding conventions.
> 1. In the __call__ I save a reference to the object. Instead, I could
> simply:
>        return str(self.__class__(content))
> Is there much of a performance impact by explicitly naming intermediate
> references? (I need some of Tim Peter's performance testing scripts.)

Since o is a "fast local" (all locals are fast locals except when a
function uses exec or import *), it is very fast.  The load and store
of fast locals are about the fastest opcodes around.

I am more worried about the inefficiency of instantiating
self.__class__ and then throwing it away after calling str() on it.
You could factor out the body of __str__ into a separate method so
that you can invoke it from __call__ without creating an instance.

> 2. I chose the slightly indirect str(o) instead of o.__str__(). Is this
> slower? Is one style preferred over the other and why?

str(o) is preferred.  I would say that you should never call __foo__
methods directly except when you're overriding a base class's __foo__

> 3. I used a format string, '<!-- %s -->' % self.content, where I could just
> as easily have concatenated '<!-- ' + self.content + ' -->'
> instead. Is one faster than the other?

You could time it.  My personal belief is that for more than one +
operator, %s is faster.

> 4. Is there any documentation that covers these kinds of issues
> where there is more than one way to do something? I'd like to have
> some foundation for making these decisions. As you can probably
> guess, I usually hate having more than one way to do anything. ;-)

I'm not aware of documentation, and I think you should give yourself
some credit for having a personal opinion.  Study the standard library
and you'll get an idea of what's "done" and what's "not done".

BTW I have another gripe about your example.

>     def __str__(self):
>         return '<!-- %s -->' % self.content
>     def __repr__(self):
>         return repr(self.__str__())

This definition of __repr__ makes no sense to me -- all it does is add
string quotes around the contents of the string (and escape
non-printing characters and quotes if there are any).  That is
confusing, because it will appear to the reader as if the object is a
string.  You probably should write

    __repr__ = __str__


--Guido van Rossum (home page: http://www.python.org/~guido/)