Simon Engledew's Blog

Eldritch nomenclature, conjoured for arcane contraptions to execute unerringly.

July 24, 2009 at 1:56am
home

Flyweighting in Python Redux

I just expanded the Flyweighted Object class to support keyword arguments:

import weakref
import cPickle

class FlyweightedObject(object):
    _pool = weakref.WeakValueDictionary()

    def __new__(klass, *args, **kwargs):
        if not hasattr(klass.__init__, 'im_func'): raise 'cannot flyweight an object which has no python constructor'

        arguments = {}

        constructor = klass.__init__.im_func
        arguments_missing = constructor.func_code.co_argcount - len(args) - 1

        if arguments_missing > 0:
            args += constructor.func_defaults[-arguments_missing:]

        varnames = constructor.func_code.co_varnames[1:]

        for i in range(len(varnames)):
            varname = varnames[i]
            arguments[varname] = kwargs.get(varname, args[i])

        key = cPickle.dumps((klass, arguments))
        instance = klass._pool.get(key, None)

        if instance is None:
            instance = object.__new__(klass)
            klass._pool[key] = instance

        return instance

    def __getnewargs__(self):
        if hasattr(self.__class__.__init__, 'im_func'):
            constructor = self.__class__.__init__.im_func
            return tuple(getattr(self, attr) for attr in constructor.func_code.co_varnames[1:])
        return tuple()