I wrote this code a simple dependency injection capability in my application. Hopefully the comments should be self explanatory.
If you want to just understand the usage, see the class decorator usage on lines 52 and 63 and the code from line 69 onwards
# Global registry for instance registrationresource_registry={}defprovides(name):"""Class decorator for an instance provider. The name passed in is what the attribute is called. The instance will be auto registered in the registry with the value of the handle TODO : the name could also be a function which could return the attribute name to extract the instance name from """defwrapper(cls):definit_and_register(init):definner(self,*args,**kwargs):"The new wrapper constructor"# Call the old constructorinit(self,*args,**kwargs)# Update the resource registry with the desired key and instanceresource_registry[self.__dict__[name]]=selfreturninner# Replace the constructor with a wrapped constructorcls.__init__=init_and_register(cls.__init__)returnclsreturnwrapperdefrequires(*resource_types):""" Class decorator to inject instances from the registry into the instance under construction"""defwrap_constructor(self,*args,**kw):"The constructor wrapper"# First call the original constructorself.__oldinit__(*args,**kw)# If this instance requires dependencies to be injectedifhasattr(self,'_resource_types'):# for each dependencyforresource_typeinself._resource_types:# inject the dependency directly as in instance variable # from the resource registryself.__dict__[resource_type]=resource_registry[kw[resource_type]]definner(cls):cls._resource_types=resource_typescls.__oldinit__=cls.__init__cls.__init__=wrap_constructorreturnclsreturninner# The following class indicates a sample resource provider which could be# injected. The 'handle' passed to the class decorator is the name of the attribute# whole value will be used as the key to register the instance name in the registry@provides('handle')classProvider(object):def__init__(self,handle):self.handle=handledef__str__(self):return'Provider(%s)'%self.handle# A sample user object (ie. the object into which the dependency is to be injected# The constructor needs to accept kw based arguments for the injection to happen# The requires decorator lists the attribute names under which the dependencies will# be injected into the instance of this class@requires('first','second')classUser(object):def__init__(self,**kwargs):passif__name__=='__main__':# Initialise the providers. They auto register themselves. p1=Provider('one')p2=Provider('two')# Instantiate the user. specify the key under which the# injected objects have been registered in the values of the# keyword arguments (the key being the attribute name declared# earlier in the class decorator)u=User(first='one',second='two')# Test that the dependencies have been appropriately injectedassertu.first==p1assertu.second==p2