You need to cache instances based on what arguments are passed to them.
| Python |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class MementoMetaclass(type):
cache = {}
def __call__(self, *args):
print "="*20
print "ClassObj:", self
print "Args:", args
print "="*20
cached = self.cache.get(args, None)
if not cached:
instance = type.__call__(self, *args)
self.cache.update({args:instance})
return instance
return cached
class Foo(object):
__metaclass__ = MementoMetaclass
template = ''
def __init__(self, arg1, arg2, arg3):
self.template = arg1
a = Foo(1,2,3)
b = Foo(2,3,4)
c = Foo(1,2,3)
d = Foo(2,3,4)
e = Foo(5,6,7)
f = Foo(5,6,7)
print id(a), id(b), id(c), id(d), id(e), id(f)
|
Discussion
In some situations (maybe with web toolkits) you may need to cache your instances, for example using a web toolkit, once you have an instance of a page you don't need to reinstantiate it every time a user connects.
Using this simple metaclass you will be able to have a cache of instances based on what arguments are passed.


Comments
Threading. You should be careful with this in a threaded environment. Because of the way it is constructured, two threads may share an instance, but won't necessarily do so. Only with proper locking can you ensure that only one instance will exist for a particular set of parameters.
If you do not want threads to share instances you must instead implement a pool mechanism, where you fetch objects from a pool, or if the pool has no appropriate instance you create the object. The objects themselves should probably be wrappers in that case, so that you can override __del__ so that it returns the instance to the pool just before it is garbage collected. Alternately, you can insist that any threads that fetch an object explicitly return it to the pool when they are done, or any classes implement a __del__ method themselves.
You don't really need a metaclass here ... you could just instantiate your instances with a factory function. It would also be clearer to your users. Unless you want to hide the fact that instances are cached and you want your users use the standard instantiation syntax. If this is your goal (for instance because there is a lot of already written code using the standard calling syntax) then the metaclass solution is justified. But I would not use it if I was writing a new application from scratch.
Sign in to comment