I understand your point. I have read several blog entries discussing the viability of DI in dynamic languages, including ruby and python. In fact, I'm writing a blog article to talk about this very subject which should be published soon.
Have you looked http://springpython.webfactional.com...config-object? It shows our pure python container, which means no XML. Instead, something that is DSL-like in nature, and doesn't depend on too much reflection.
Code:
from springpython.config import *
from springpython.context import *
class MovieBasedApplicationContext(PythonConfig):
def __init__(self):
super(MovieBasedApplicationContext, self).__init__()
@Object(scope.PROTOTYPE)
def MovieLister(self):
lister = MovieLister()
lister.finder = self.MovieFinder()
lister.description = self.SingletonString()
self.logger.debug("Description = %s" % lister.description)
return lister
@Object(scope.SINGLETON)
def MovieFinder(self):
return ColonMovieFinder(filename="support/movies1.txt")
@Object # scope.SINGLETON is the default
def SingletonString(self):
return StringHolder("There should only be one copy of this string")
This lets you stick with python and not even think about XML.
I'm not sure if your question was more about the XML or just DI+python in general. I will assume you are asking why do we need this DI for python? First of all, the lines inside the function calls are basically what you would have written anyway. We just scooped up this creational logic, and captured it in a centralized location. The overhead is wrapping them as method calls inside this separate class called MovieBasedApplicationContext.
There are multiple benefits to doing this. The first immediate one, is to support testing. We can tweak the creation logic for test situations, by extending this class and injecting test dummies as needed. Look at the following example where we extend the container definition, and inject a MovieFinder dummy to isolate MovieLister for test purposes. Fetching MovieLister from the container will give us an alternative configuration with minimal effort.
Code:
class MyTestableAppContext(MovieBasedApplicationContext):
def __init__(self):
super(MyTestableAppContext, self).__init__()
@Object
def MovieFinder(self):
return MovieFinderStub()
Another benefit is to inject AOP proxies. By having MovieBasedApplicationContext in place, I can tweak it to wrap MovieFinder by wrapping it in a service that will not be seen by the MovieLister or its caller. This lets us tap the connection between caller and callee, and put in useful services as needed, again with minimal effort.
Code:
from springpython.aop import *
from springpython.config import *
from springpython.context import *
class MovieBasedApplicationContext(PythonConfig):
def __init__(self):
super(MovieBasedApplicationContext, self).__init__()
@Object(scope.PROTOTYPE)
def MovieLister(self):
lister = MovieLister()
lister.finder = self.MovieFinder()
lister.description = self.SingletonString()
self.logger.debug("Description = %s" % lister.description)
return lister
# By renaming the original service to this...
def targetMovieFinder(self):
return ColonMovieFinder(filename="support/movies1.txt")
#...we can substitute a proxy that will wrap it with an interceptor
@Object(scope.SINGLETON)
def MovieFinder(self):
return ProxyFactoryObject(target=self.targetMovieFinder(),
interceptors=MyInterceptor())
@Object # scope.SINGLETON is the default
def SingletonString(self):
return StringHolder("There should only be one copy of this string")
class MyInterceptor(MethodInterceptor):
def invoke(self, invocation):
results = "<Wrapped>" + invocation.proceed() + "</Wrapped>"
return results
Other benefits are the fact that we can flexibly define scopes, like PROTOTYPE or SINGLETON. I like the fact that in one place, I can see how the app is wired from a high level perspective. This acts like the blueprints to my application. With this infrastructure in place, it is easy to think about other services to offer, like remoting, security, and transactions.
In my humble opinion, this has nothing to do with dynamic vs. static, and as I have just demonstrated this is not an XML vs. python issue either. To me, it is about the easiest way to construct the key services in your app, manage the dependencies, and make valuable adjustments as you maintain your app. I am the first to say, don't DI everything! Only DI what your TDD exposes as key injection points for your business solution. Sure it takes a little extra effort to put in this IoC container. But when used to expose the right injection points, it can save you a lot of maintenance down the road.