#!/usr/bin/env python
# -*- coding: utf-8 -*-
from inspect import getmembers, ismethod
_NOVALUE = object()
class _Memoized(object):
def __init__(self):
self.value = _NOVALUE
def __nonzero__(self):
return (self.value is not _NOVALUE)
class singleton(object):
def __init__(self, func):
self.func = func
def __call__(self):
memoized = _Memoized()
def singleton_wrapper(instance_self, *args, **kwargs):
if args or kwargs:
raise TypeError, ("Singleton-wrapped methods shouldn't take"
"any argument! (%s)" % self.func)
if not memoized:
memoized.value = self.func(instance_self)
return memoized.value
return singleton_wrapper
class prototype(object):
def __init__(self, func):
self.func = func
class _Container(object):
def __call__(self, klass):
subklass_dict = dict(klass.__dict__)
self._set_singletons(subklass_dict, klass)
self._set_prototypes(subklass_dict, klass)
return type(klass.__name__, (klass, ), subklass_dict)
def _set_singletons(self, subklass_dict, klass):
for name, singletoned in ((n, f) for (n, f) in getmembers(klass,
lambda x: isinstance(x, singleton)) ):
subklass_dict[name] = singletoned()
def _set_prototypes(self, subklass_dict, klass):
for name, prototyped in ((n, f) for (n, f) in getmembers(klass,
lambda x: isinstance(x, prototype))):
subklass_dict[name] = prototyped.func
Container = _Container()
if __name__ == "__main__":
class MySomething(object):
pass
class TheObject(object):
def __init__(self, someattr):
self.someattr = someattr
class MyContainer(object):
def __init__(self, config):
self.config = config
@singleton
def theobject(self):
return TheObject(self.config["someattr"])
@prototype
def something(self, value):
o = MySomething()
o.value = value
o.obj = self.theobject()
return o
# python >= 2.6 users can use class decorators.
MyContainer = Container(MyContainer)
mc = MyContainer({"someattr": "a"})
something1 = mc.something(1)
something2 = mc.something(2)
theobject = mc.theobject()
assert theobject.someattr == "a"
assert something1.value == 1
assert something2.value == 2
assert (something1.obj is something2.obj)
assert (something2.obj is theobject)