On Jun 11, 3:38 pm, George Sakkis <[EMAIL PROTECTED]> wrote: > On Jun 11, 8:27 am, Frank Millman <[EMAIL PROTECTED]> wrote: > > > > 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. > > > To be honest, it feels neater than setting up a property for each > > attribute. > > I don't see why this all-or-nothing approach is neater; what if you > have a hundred expensive computed attributes but you just need one ? > Unless you know this never happens in your specific situation because > all missing attributes are tightly coupled, properties are a better > way to go.
It so happens that this is my specific situation. I can have a foreign key column in one table with a reference to a primary key column in another table. I have for some time now had the ability to set up a pseudo-column in the first table with a reference to an alternate key column in the second table, and this requires various attributes to be set up. I have recently extended this concept where the first table can have a pseudo-column pointing to a column in the second table, which is in turn a pseudo-column pointing to a column in a third table. This can chain indefinitely provided that the end of the chain is a real column in the final table. My problem is that, when I create the first pseudo-column, the target column, also pseudo, does not exist yet. I cannot call it recursively due to various other complications. Therefore my solution was to wait until I need it. Then the first one makes a reference to the second one, which in turn realises that in needs a reference to the third one, and so on. So it is recursive, but at execution-time, not at instantiation-time. Hope this makes sense. >The boilerplate code can be minimal too with an appropriate > decorator, something like: > > class A(object): > > def __init__(self,x,y): > self.x = x > self.y = y > > @cachedproperty > def z(self): > return self.x * self.y > > where cachedproperty is > > def cachedproperty(func): > name = '__' + func.__name__ > def wrapper(self): > try: return getattr(self, name) > except AttributeError: # raised only the first time > value = func(self) > setattr(self, name, value) > return value > return property(wrapper) > This is very neat, George. I will have to read it a few more times before I understand it properly - I still have not fully grasped decorators, as I have not yet had a need for them. Actually I did spend a bit of time trying to understand it before posting, and I have a question. It seems that this is now a 'read-only' attribute, whose value is computed by the function the first time, and after that cannot be changed. It would probably suffice for my needs, but how easy would it be to convert it to read/write? Thanks Frank -- http://mail.python.org/mailman/listinfo/python-list