Copy constructors

Andrew Dalke dalke at acm.org
Tue Aug 14 07:05:00 EDT 2001


Guido:
>No, in the new system, __getattr__ is called for all attributes.  See
>my response to Roman.

I hadn't noticed this __getattr__ change on my previous readings.

I confess I couldn't find that response - perhaps my newsserver
dropped it?  But I do see a post of yours with no attribution of
who you are responding to, which says:

> new-style classes allow you to
> overload __getattr__ for all attribute accesses -- classic classes
> only call __getattr__ when "normal" attribute access fails, which is
> less flexible.

I want to point out that the current ("old-style") behaviour is
very usful for caching results.  I have written several classes
of the form

class Obj:
  def __getattr__(self, name):
    if name == "prop1":
        compute prop1
        self.prop1 = prop1
        return prop1
    elif name == "prop2":
       ...
    raise AttributeError(name)

For example, one is a system where the "compute prop" calls a
C function, and another version talks to a database to get the
requested information.

In both cases, I liked the simplicity of implementation and the
fact that once cached there is no performance loss.

With the new-style __getattr__ this means the code will be
slightly more complicated, as in

  def __getattr__(self, name):
    if name in self.__dict__:
      return self.__dict__[name]
    ... code as usual ...

and definitely slower.

Yes, I am concerned about the performance.  Instead of using
__getattr__/__setattr__ to mimic attribute lookup I could also
have done C++/Java style accessor methods

  def getProp1(self):
     ...
  def setProp1(self):
     ...

I happen to think accessor functions look ugly - things that
are attributes should look like attributes.  I've been able to
argue against them because __*attr__ exists partially because I
can say "and the results can be cached with no performance loss."
But now it appears that getProp1()/setProp1() methods will never
be slower than __getattr__, so I will only have an esthetic
argument to justify my preference.

I do understand that not having a __getattr__ hook for all attribute
lookups is less flexible.  I just not that I've much more often
used this caching lookup ability than needed that flexibility.  In
fact, I'm hard pressed to think of a case where I have needed more
flexibility.

>I'd like to see which is more common -- the need to change __class__
>or the need to inherit from a built-in type.  I'm betting the latter,
>by a large amount.

I've derived from UserList and UserDict, many more times then I've
changed __class__.  I've also derived from them many more than I've
used the dis, netrc, or mailcap modules, or used complex numbers
or unicode, or specified a PYTHONSTARTUP variable for interactive use.
Should those features also be removed?

                    Andrew
                    dalke at dalkescientific.com






More information about the Python-list mailing list