Could an object delegate itself into another?

Michael Hudson mwh21 at cam.ac.uk
Thu Oct 21 16:22:43 EDT 1999


=?ISO-8859-1?Q?Fran=E7ois_Pinard?= <pinard at iro.umontreal.ca> writes:

> Hi, people.  Here I am, with another question.
> 
> In one program, I keep a registry of created objects into a dictionary.
> Objects register themselves through their __init__ method.  From outside
> the class, I check if a given object has already been created, so to avoid
> creating another one that would be too similar, kind of redundant.
> 
> It would be neat if I could hide this check.  The ideal would be that the
> instantiating call returns an already existing similar object if it exists,
> instead of a brand new one.  A simple trick is to not instantiate directly,
> but through some service function that does the check, returning either
> the old object, or a brand new one.
> 
> But yet, I wonder.  Could an object really delegates itself into another?
> For example, is there some way by which a newly created object could
> soon check, probably within __init__, if a similar copy has already been
> registered?  If one similar object is found, this newly created object would
> immediately dismiss itself in favour of the previous one, and the genuine
> class instantiator would return the previous object.  Is that possible?

Not 100% sure I understand your problem. I seem to be having trouble
thinking of ways of explaining what I actually want to say here, so
let's just have an example:

class _Class:
    def __init__(self,i):
        self.i = i
    def __repr__(self):
        return "hello, i'm number " + `self.i`

_cache = {}

def Class(i):
    if not _cache.has_key(i):
         _cache[i] = _Class(i)
    return _cache[i]

a = Class(1)
b = Class(2)
c = Class(1)

print "a", a, id(a)
print "b", b, id(b)
print "c", c, id(c)

yields:

a hello, i'm number 1 135367104
b hello, i'm number 2 135369136
c hello, i'm number 1 135367104

The point is that you think you're calling a class constructor when
you execute

a = Class(1)

but you're not. Who's going to know?

Also I think it's cleaner to have the caching mechanism outside of the
class itself. You need to be on the lookout for cycles when doing this
sort of stuff, and if the instance has a reference to the cache which
has a reference to the instance, that's a cycle.

You could probably whip up a class that encapsulates caching, lets
see:

class Cacher:
    def __init__(self,klass):
        self.klass = klass
        self.cache = {}
    def __call__(self, *args, **kwargs):
        if not self.cache.has_key((args,kwargs)):
             self.cache[(args,kwargs)] = apply(self.klass, args, kwargs)
        return self.cache[(args,kwargs)]

then:

Class = Cacher(_Class) # _Class from above...

but frankly, the first version is hardly a major trauma to write and
will perform better in space and time, so I'd go with that.

do-you-think-this-is-snippet-material-Hans?-ly y'rs Michael




More information about the Python-list mailing list