Postpone creation of attributes until needed

Steven D'Aprano steve at
Tue Jun 12 13:18:40 CEST 2007

On Mon, 11 Jun 2007 22:35:46 -0700, Frank Millman wrote:

> On Jun 12, 1:46 am, Steven D'Aprano
> <s... at> wrote:
>> >> You haven't told us what the 'compute' method is.
>> >> Or if you have, I missed it.
>> > Sorry - I made it more explicit above. It is the method that sets up
>> > all the missing attributes. No matter which attribute is referenced
>> > first, 'compute' sets up all of them, so they are all available for
>> > any future reference.
>> If you're going to do that, why not call compute() from your __init__ code
>> so that initializing an instance sets up all the attributes?
> Because, as I have tried to explain elsewhere (probably not very
> clearly), not all the information required to perform compute() is
> available at __init__ time.

I'm sorry, but this explanation doesn't make sense to me.

Currently, something like this happens:

(1) the caller initializes an instance
=>  instance.x = some known value
=>  instance.y is undefined
(2) the caller tries to retrieve instance.y
(3) which calls instance.__getattr__('y')
(4) which calls instance.compute()
=>  which forces the necessary information to be available
=>  instance.__dict__['y'] = some value
(5) finally returns a value for instance.y

Since, as far as I can tell, there is no minimum time between creating the
instance at (1) and trying to access instance.y at (2), there is no
minimum time between (1) and calling compute() at (4), except for the
execution time of the steps between them. So why not just make compute()
the very last thing that __init__ does?

> I have gained a lot of valuable advice from this thread, but I do have
> a final question.
> Every respondent has tried to nudge me away from __getattr__() and
> towards property(), but no-one has explained why. 

Not me! I'm trying to nudge you away from the entire approach!

> What is the downside of my approach? 

It is hard to do at all, harder to do right, more lines of code, more bugs
to fix, slower to write and slower to execute.

> And if this is not a good case for using
> __getattr__(), what is? What kind of situation is it intended to
> address?

Delegation is probably the poster-child for the use of __getattr__. Here's
a toy example: a list-like object that returns itself when you append to
it, without sub-classing.

class MyList:
    def __init__(self, *args):
        self.__dict__['data'] = list(args)
    def __getattr__(self, attr):
        return getattr(, attr)
    def __setattr__(self, attr, value):
        return setattr(, attr, value)
    def append(self, value):
        return self


More information about the Python-list mailing list