How to automate accessor definition?

Alf P. Steinbach alfps at start.no
Mon Mar 22 10:22:02 EDT 2010


* kj:
> In <mailman.1030.1269194878.23598.python-list at python.org> Dennis Lee Bieber <wlfraed at ix.netcom.com> writes:
> 
>> On Sun, 21 Mar 2010 16:57:40 +0000 (UTC), kj <no.email at please.post>
>> declaimed the following in gmane.comp.python.general:
> 
>>> Regarding properties, is there a built-in way to memoize them? For
>>> example, suppose that the value of a property is obtained by parsing
>>> the contents of a file (specified in another instance attribute).
>>> It would make no sense to do this parsing more than once.  Is there
>>> a standard idiom for memoizing the value once it is determined for
>>> the first time?
>>>
>> 	Pickle, Shelve? Maybe in conjunction with SQLite3...
> 
> I was thinking of something less persistent; in-memory, that is.
> Maybe something in the spirit of:
> 
> @property
> def foo(self):
>     # up for some "adaptive auto-redefinition"?
>     self.foo = self._some_time_consuming_operation()
>     return self.foo
> 
> ...except that that assignment won't work! It bombs with "AttributeError:
> can't set attribute".

Since foo is a read only property you can assign to it.

But it doesn't matter: if it worked technically it wouldn't give you what you're 
after, the once-only evaluation.

A simple way to do that, in the sense of copying code and having it work, is to 
use a generator that, after evaluating the expensive op, loops forever yielding 
the resulting value.

A probably more efficient way, and anyway one perhaps more easy to understand, 
is as follows:


<code>
from __future__ import print_function

class LazyEval:
     def __init__( self, f ):
         self._f = f
         self._computed = False

     @property
     def value( self ):
         if not self._computed:
             self._value = self._f()
             self._computed = True
         return self._value

class HiHo:
     def _expensive_op( self ):
         print( "Expensive op!" )
         return 42

     def __init__( self ):
         self._foo = LazyEval( self._expensive_op )

     @property
     def foo( self ):
         return self._foo.value

o = HiHo()
for i in range( 5 ):
     print( o.foo )
</code>


Cheers & hth.,

- Alf



More information about the Python-list mailing list