1. Jonathan Eunice
  2. mementos

Source

mementos / mementos.py

class MementoMetaclass(type):
    """
    Classes that use this caching metaclass will have their instances
    automatically cached based on instantiation-time arguments (i.e. to __init__).
    Super-useful for not repetitively creating expensive-to-create objects.
    
    See http://code.activestate.com/recipes/286132-memento-design-pattern-in-python/
    """
    cache = {}

    def __call__(self, *args, **kwargs):
        key = (self, ) + args + tuple(kwargs.items())
        try:
            return self.cache[key]
        except KeyError:
            instance = type.__call__(self, *args, **kwargs)
            self.cache[key] = instance
            return instance


if __name__ == '__main__':
    
    class Thing(object):
        
        __metaclass__ = MementoMetaclass
        
        def __init__(self, name):
            self.name = name
        

    t1 = Thing("one")
    t2 = Thing("one")
    assert t1 is t2
    
    o1 = Thing("lovely")
    o2 = Thing(name="lovely")
    assert o1 is not o2   # because the call signature is different
    
    class OtherThing(object):
            
        __metaclass__ = MementoMetaclass
        
        def __init__(self, name):
            self.name = name
            self.color = None
            self.weight = None
            
        def set(self, color=None, weight=None):
            self.color = color or self.color
            self.weight = weight or self.weight
            return self
    
    ot1 = OtherThing("one").set(color='blue')
    ot2 = OtherThing("one").set(weight='light')
    assert ot1 is ot2
    assert ot1.color == ot2.color == 'blue'
    assert ot1.weight == ot2.weight == 'light'

    print "working as designed!"