[Python-Dev] OT: Performance vs. Clarity vs. Convention
Patrick K. O'Brien
pobrien@orbtech.com
Wed, 5 Jun 2002 21:15:51 -0500
[Guido van Rossum]
>
> 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.
Some more code from the module might help explain this design decision. I'm
still sort of toying with this to see if I like it. The basic idea here is
that I'm trying to support both DOM-like xhtml structures as well as simple
function-like callables that return strings. When the instance is called it
needs a fresh state in order to better mimic a true function. It isn't
immediately obvious to me how I might refactor this to avoid instantiating a
throwaway.
class Element:
def __init__(self, klass, id, style, title):
self.name = self.__class__.__name__.lower()
self.attrs = {
'class': klass, # Space-separated list of classes.
'id': id, # Document-wide unique id.
'style': style, # Associated style info.
'title': title, # Advisory title/amplification.
}
def attrstring(self):
attrs = self.attrs.keys()
attrs.sort() # Sorting is only cosmetic, not required.
l = [] # List of formatted attribute/value pairs.
for attr in attrs:
value = self.attrs[attr]
if value is not None and value != '':
l += ['%s="%s"' % (attr, convert(value))]
s = ' ' + ' '.join(l) # Prepend a single space.
return s.rstrip() # Reduce to an empty string if no attrs.
def __str__(self):
pass
def __repr__(self):
return repr(self.__str__())
class EmptyElement(Element):
def __init__(self, klass=None, id=None, style=None, title=None):
Element.__init__(self, klass, id, style, title)
def __call__(self, klass=None, id=None, style=None, title=None):
o = self.__class__(klass, id, style, title)
return str(o)
def __str__(self):
attrstring = self.attrstring()
return '<%s%s />\n' % (self.name, attrstring)
class SimpleElement(Element):
def __init__(self, content='', klass=None, id=None, style=None,
title=None):
self.content = content
Element.__init__(self, klass, id, style, title)
def __call__(self, content='', klass=None, id=None, style=None,
title=None):
o = self.__class__(content, klass, id, style, title)
return str(o)
def __str__(self):
attrstring = self.attrstring()
return '<%s%s>\n%s\n</%s>\n' % \
(self.name, attrstring, convert(self.content), self.name)
class Br(EmptyElement): pass
class Hr(EmptyElement): pass
class P(SimpleElement): pass
# The following singleton instances are callable, returning strings.
# They can be used like simple functions to return properly tagged contents.
br = Br()
comment = Comment()
hr = Hr()
p = P()
> 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.
Yes. This was a conscious design choice for this particular application.
Maybe there is a better way, and maybe I'm not being too Pythonic, but I'm
not particularly troubled by this even though I know I'm "breaking the
rules".
I guess I don't mind if there is more than one way to do something, as long
as one way is the Python way and the other way is my way. ;-)
---
Patrick K. O'Brien
Orbtech