[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__
method.
> 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__
instead.
--Guido van Rossum (home page: http://www.python.org/~guido/)