I recant my IoC! IoC containers in dynamic languages are silly.
If any code snippets or content appear broken or missing, you can find this same post with its full content at blog.foundev.pro.
After a year or so of solid Alt Dot Net infection (as far as infections go its a pretty awesome one to have), I decided to give Python a try again for more than one off sysadmin tasks, and to actually dive into it as a newly minted “Agilista”.
However, I had a problem..there were no non-painful IoC containers in Python (sorry to the other authors of IoC frameworks in Python like Spring Python and Snake Guice, I know you try and I respect the effort). Ultimately, I could not imagine coding anymore without something to handle all my registration for me, that’d dynamically inject in my dependencies, give me hooks for contextual resolution, and give me rich interception support.
So I built my own, it was painful still, but I had some ideas to move it in an Convention Over Configuration direction, and ultimately get within shooting range of what fancy stuff we’ve come to expect in .Net that Windsor, StructureMap and many others provide.
Now as I got into the fancier aspects of dynamic languages, open classes and the ability to override all behavior easily I get it…a dynamic languages runtime is like a bit IoC container.
Now I’ve heard other people say this many times but rarely with explanation or example, or focus on frankly silly things like “Dependency Injection adds too many lines of code” which is a bit melodramatic. Two arguments to a constructor, two fields ,and then avoiding having to call new is not “adding too many lines of code”, especially with templates, IDE’s, scripting, etc to cut down the actual typing load.Today I’m going to actually try to explain how languages like Python, Ruby etc give us the same awesomeness we’ve come to expect in things like Windsor..but at a much cheaper cost of learning and dev time.
Take a typical resolution scenario where you want to output to a different file format depending on command line switches. With an IoC container you can either:
Change the resolution argument to load a different concrete type:
if(arg == “XML”)
{
container.Register(Component.For().ImpmentedBy ());
}
else if(arg == “HTML”)
{
container.Register(Component.For().ImpmentedBy ());
}
else
{
container.Register(Component.For().ImpmentedBy ());
}
or resolve different arguments or keys using a service locator approach in later client code (thereby depending on the container)
public void output(IKernel container, string key)
{
var output =container.Resolve(key);
output.save();<p> <span style="color:#0000ff">}</span> </div> </div> </blockquote> <p> or implement a custom implementation of the resolver system (which I’ll leave out for the sake of brevity, but it’s not instant code).  Also to do all this you have to depend on interfaces, add all your interchangeable code to the constructor and life is grand.  You do this for many reasons in static languages, its the only way to get easy testability and code that is open to extension.  In dynamic languages its <strong><u>always open for extension and easy to test</u></strong> . Let me demonstrate: </p> <blockquote> <div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent"> <div style="font-family:consolas,lucida console,courier,monospace"> <span style="color:#008800"><b>import</b></span> <span style="color:#bb0066"><b>outputlib</b></span> <span style="color:#008800"><b>as</b></span> <span style="color:#bb0066"><b>o</b></span></p> <p> <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>outputselect</b></span>(arg):<br /> <span style="color:#008800"><b>if</b></span> arg == <span style="color:#dd2200">“XML”</span>:<br /> o.Output = XmlOutput<br /> <span style="color:#008800"><b>elif</b></span> arg == <span style="color:#dd2200">“HTML”</span>:<br /> o.Output = HtmlOutput<br /> <span style="color:#008800"><b>else</b></span>:<br /> o.Output = NullOutput </p> <p> <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>saveoutput</b></span>():<br /> o.Output().save()  <span style="color:#888888">#will save whichever</span> </div> </div> </blockquote> <blockquote> <p> Contextual resolution in a nutshell, and throughout your code if need be.  “Interception” is even easier, take a look at <a title="http://docs.python.org/dev/library/functools.html" href="http://docs.python.org/dev/library/functools.html">http://docs.python.org/dev/library/functools.html</a> and then start playing you’ll see you can trivially apply logging and security to methods without explicitly adding it. A short logging example follows: </p> </blockquote> <blockquote> <div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent"> <div style="font-family:consolas,lucida console,courier,monospace"> <span style="color:#008800"><b>import</b></span> <span style="color:#bb0066"><b>types</b></span> <br /> <span style="color:#008800"><b>import</b></span> <span style="color:#bb0066"><b>functools</b></span></p> <p> <span style="color:#888888">#applies a cepter to each non-underscored method.</span><br /> <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>wrapcls</b></span>(cls, cepter):<br />     publics  = [ name <span style="color:#008800"><b>for</b></span> name <span style="color:#008800">in</span> <span style="color:#003388">dir</span>(cls) <span style="color:#008800"><b>if</b></span> <span style="color:#008800">not</span> name.startswith(<span style="color:#dd2200">“_”</span>)] <br />     methods = [<span style="color:#003388">getattr</span>(cls,method) <span style="color:#008800"><b>for</b></span> method <span style="color:#008800">in</span> publics <span style="color:#008800"><b>if</b></span> <span style="color:#003388">type</span>(<span style="color:#003388">getattr</span>(cls,method)) == types.MethodType ]<br />     <span style="color:#008800"><b>for</b></span> method <span style="color:#008800">in</span> methods:<br />         intercepted_method = cepter(method)<br />         <span style="color:#003388">setattr</span>(cls, method.__name__, intercepted_method) <span style="color:#888888">#attaches intercepted_method to the original class, replacing non-intercepted one</span> </p> <p> <span style="color:#888888">#the magic all happens in the functools.wraps decorator</span><br /> <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>loggingcepter</b></span>(func):<br />     <span style="color:#555555">@functools</span>.wraps(func)<br />     <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>logafter</b></span>(*args, **kwargs): <span style="color:#888888">#for csharp devs view this as an inline delegate</span><br />         result = func(*args, **kwargs) <span style="color:#888888">#invoking function</span><br />         <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“function name: ”</span> + func.__name__<br />         <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“arguments were: ”</span><br />         <span style="color:#008800"><b>for</b></span> a <span style="color:#008800">in</span> args:<br />             <span style="color:#008800"><b>print</b></span> <span style="color:#003388">repr</span>(a)<br />         <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“keyword args were: ”</span><br />         <span style="color:#008800"><b>for</b></span> kword <span style="color:#008800">in</span> kwargs:<br />            <span style="color:#008800"><b>print</b></span> <span style="color:#003388">repr</span>(kword) + <span style="color:#dd2200">“ : ”</span> + <span style="color:#003388">repr</span>(kwargs[kword])<br />         <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“return value was: ”</span> + <span style="color:#003388">repr</span>(result)<br />         <span style="color:#008800"><b>return</b></span> result<br />     <span style="color:#008800"><b>return</b></span> logafter<br />     <br /> <span style="color:#888888">#default boring repository class</span><br /> <span style="color:#008800"><b>class</b></span> <span style="color:#bb0066"><b>StorageEngine</b></span>(<span style="color:#003388">object</span>):<br />     <span style="color:#555555">@property</span><br />     <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>connections</b></span>(<span style="color:#003388">self</span>):<br />         <span style="color:#008800"><b>pass</b></span><br />     <br />     <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>_sessioncall</b></span>(<span style="color:#003388">self</span>):<br />         <span style="color:#008800"><b>pass</b></span><br />         <br />     <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>create</b></span>(<span style="color:#003388">self</span>,user):<br />         <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“running create now from the method”</span><br />          <br />     <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>delete</b></span>(<span style="color:#003388">self</span>, <span style="color:#003388">id</span>):<br />         <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“running delete now from the method”</span><br />         <span style="color:#008800"><b>return</b></span> <span style="color:#dd2200">“deleted from the database”</span><br />         <br />     <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>get</b></span>(<span style="color:#003388">self</span>, <span style="color:#003388">id</span>):<br />         <span style="color:#008800"><b>pass</b></span><br />         <br />     <span style="color:#008800"><b>def</b></span> <span style="color:#0066bb"><b>__init__</b></span>(<span style="color:#003388">self</span>):<br />         <span style="color:#008800"><b>pass</b></span> </p> <p> <span style="color:#888888">#placeholder storage object</span><br /> <span style="color:#008800"><b>class</b></span> <span style="color:#bb0066"><b>User</b></span>(<span style="color:#003388">object</span>):<br />     <span style="color:#008800"><b>pass</b></span><br />             <br /> wrapcls(StorageEngine ,loggingcepter)<br /> repo = StorageEngine()<br /> <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“calling count this should not be intercepted”</span><br /> cnncount = repo.connections<br /> <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“now get should be intercepted”</span><br /> repo.get(<span style="color:#0000DD"><b>1</b></span>)<br /> <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“we should see keyword arguments here”</span><br /> repo.delete(<span style="color:#003388">id</span>=<span style="color:#0000DD"><b>2</b></span>)<br /> <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“session call should not be intercepted”</span><br /> repo._sessioncall()<br /> <span style="color:#008800"><b>print</b></span> <span style="color:#dd2200">“create should be intercepted and we should see a User object”</span><br /> repo.create(User()) </div> </div> </blockquote> <p>   </p> <p> Running the above script should result in the following output </p> <p>   </p> <blockquote> <p> <a href="https://lostechies.com/content/ryansvihla/uploads/2011/03/Screenshot20091116at4.20.56PM_0C117192.png"><img style="border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px" border="0" alt="Screen shot 2009-11-16 at 4.20.56 PM" src="https://lostechies.com/content/ryansvihla/uploads/2011/03/Screenshot20091116at4.20.56PM_thumb_49A1600C.png" width="625" height="530" /></a> </p> <p> So this is all very cool, but what does it mean or why do I care?  For those of us used to using a proper IoC container like Windsor or StructureMap, we’ve gotten used to have capabilities like the above easily available to us when we’ve needed them. It’s nice to find that in Python (or really any dynamic language ) we can easily build our own similar functionality that we’ve come to depend on.  We’re never coupled and we’re always able to test and mock out behavior.  It was a long time coming but I think I finally get it now. </p> </blockquote>
