Easy caching

J

jalanb3

Evening all,

And thank you for your valuable reading skills.

The following pattern turned up in coding tonight.
It works, but I'm suspicious, it just seems too easy.

So any comments or constructive criticisms welcome ?

*** Start doctest format ***

>>> class Cacher:
... def __init__(self):
... self.value_in_database = 0
...
... def very_slow_database_access(self):
... return self.value_in_database
...
... @property
... def show(self):
... result = self.very_slow_database_access()
... self.show = result
... return result
...
>>>

Create an instance
>>> cacher = Cacher()

Someone writes to the database

>>> cacher.value_in_database = 9

Call show as a method, get the value
>>> print cacher.show
9

show is now a cached string
>>> print cacher.show
9

show is not a method so
if someone else writes to the database
we will not see the change

>>> cacher.value_in_database = 7
>>> print cacher.show
9

To force another read from the database
delete the string attribute

>>> del cacher.show

Next time we try to use the attribute
Python will find the method again

>>> print cacher.show
7

***
 
P

Peter Otten

jalanb3 said:
Evening all,

And thank you for your valuable reading skills.

The following pattern turned up in coding tonight.
It works, but I'm suspicious, it just seems too easy.

So any comments or constructive criticisms welcome ?

*** Start doctest format ***

... def __init__(self):
... self.value_in_database = 0
...
... def very_slow_database_access(self):
... return self.value_in_database
...
... @property
... def show(self):
... result = self.very_slow_database_access()
... self.show = result
... return result
...

The above only works because properties don't work with classic class. If
you make Cacher a newstyle class (have it inherit from object) you'll get
an AttributeError. Therefore I think it would be cleaner to either

use __getattr__() or

change the Cacher to something like

class Cacher(object):
def __init__(self):
self._show = None
# ...

@property
def show(self):
result = self._show
if result is None:
result = self._show = self.very_slow_database_access()
return result

Peter
 
M

M.-A. Lemburg

The above only works because properties don't work with classic class. If
you make Cacher a newstyle class (have it inherit from object) you'll get
an AttributeError. Therefore I think it would be cleaner to either

use __getattr__() or

change the Cacher to something like

class Cacher(object):
def __init__(self):
self._show = None
# ...

@property
def show(self):
result = self._show
if result is None:
result = self._show = self.very_slow_database_access()
return result

You should also consider not using a property for this at all.

Attribute access is supposed to be fast and, if at all, only cause
AttributeErrors.

Your self.very_slow_database_access() call can raise all sorts of
errors and likely take much too long for what a casual user would
expect from writing print (cache.show).

It's much better to write this as method which then uses an
instance attribute for caching the value read from the database.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Nov 13 2008)________________________________________________________________________

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top