2008/2/8, Freek Dijkstra <[EMAIL PROTECTED]>: > Is there a best practice on how to override __new__? > > I have a base class, RDFObject, which is instantiated using a unique > identifier (a URI in this case). If an object with a given identifier > already exists, I want to return the existing object, otherwise, I > want to create a new object and add this new object to a cache. I'm > not sure if there is a name for such a creature, but I've seen the > name MultiSingleton in the archive. > > This is not so hard; this can be done by overriding __new__(), as long > as I use a lock in case I want my code to be multi-threading > compatible. > > import threading > threadlock = threading.Lock() > > class RDFObject(object): > _cache = {} # class variable is shared among all RDFObject > instances > def __new__(cls, *args, **kargs): > assert len(args) >= 1 > uri = args[0] > if uri not in cls._cache: > threadlock.acquire() # thread lock > obj = object.__new__(cls) > cls._cache[uri] = obj > threadlock.release() # thread unlock. > return cls._cache[uri] > def __init__(self, uri): > pass > # ... > > However, I have the following problem: > The __init__-method is called every time you call RDFObject(). > > The benefit of this multi-singleton is that I can put this class in a > module, call RDFObject(someuri), and simply keep adding states to it > (which is what we want). If it had some state, good, that is retained. > If it did not have so: fine, we get a new object. > For example: > > x = RDFObject(someuri) > x.myvar = 123 > ...later in the code... > y = RDFObject(someuri) > assert(y.myvar == 123) > > I and fellow programmers tend to forget about the __init__() catch. > For example, when we subclass RDFObject: > > class MySubclass(RDFObject): > def __init__(self, uri): > RDFObject.__init__(self, uri) > self.somevar = [] > > Now, this does not work. The array is unwantedly initialized twice: > > x = RDFObject(someotheruri) > x.somevar.append(123) > ...later in the code... > y = RDFObject(someotheruri) > assert(y.somevar[0] == 123) > > So I'm wondering: is there a best practice that allows the behaviour > we're looking for? (I can think of a few things, but I consider them > all rather ugly). Is there a good way to suppress the second call > __init__() from the base class? Perhaps even without overriding > __new__? > > -- > http://mail.python.org/mailman/listinfo/python-list > Would something like this be acceptable ?
class memoize(object): def __init__(self, func): self._memoized = {} self._func = func def __get__(self, instance, *args): self._instance = instance return self def __call__(self, *args, **kwargs): uri = args[0] if uri not in self._memoized: self._memoized[uri] = self._func(self._instance, *args, **kwargs) return self._memoized[uri] class Memoize(type): @memoize def __call__(cls, *args, **kwargs): return super(Memoize, cls).__call__(*args, **kwargs) class RDFObject(object): __metaclass__ = Memoize def __init__(self, uri): self.uri = uri print self.__class__, uri class Test2(RDFObject): def __init__(self, uri): super(Test2, self).__init__(uri) self.mylist = [] x = Test2("oi") print x.uri x.mylist.append(32) y = Test2("oi") print y.uri print y.mylist z = Test2("oa") print z.uri print z.mylist I haven't used this before, but looks like some people have done similar things. There are some possible problems you will encounter with this, if you create an instance of RDFObject("oa") after creating an instance Test2("oa") it will contain mylist attribute (for example). -- -- Guilherme H. Polo Goncalves -- http://mail.python.org/mailman/listinfo/python-list