class FlyweightFactory(object):
    def __init__(self, cls):
        self._cls = cls
        self._instances = dict()

    def get_instance(self, *args, **kargs):
        return self._instances.setdefault(
                                (args, tuple(kargs.items())),
                                self._cls(*args, **kargs))


#----------------------------------------------------------
class Spam(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b


class Egg(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


SpamFactory = FlyweightFactory(Spam)
EggFactory = FlyweightFactory(Egg)

assert SpamFactory.get_instance(1, 2) is SpamFactory.get_instance(1, 2)
assert EggFactory.get_instance('a', 'b') is EggFactory.get_instance('a', 'b')
assert SpamFactory.get_instance(1, 2) is not EggFactory.get_instance(1, 2)

# Subclassing a flyweight class
class SubSpam(Spam):
    pass

SubSpamFactory = FlyweightFactory(SubSpam)

assert SubSpamFactory.get_instance(1,2) is SubSpamFactory.get_instance(1,2)
assert SpamFactory.get_instance(1,2) is not SubSpamFactory.get_instance(1,2)
