6 ms·
Dependency Injection for Python
- antonwinter 13y agothat looks pretty good. not sure if i overlooked it in the notes or not, but i have a couple questions. you mentioned copyright at the end. what sort of license are you releasing it under? Does it support nested creation of objects? ( ie if you ask for an instance of class 'FOO' and FOO has a DI or 'BAR' will BAR be first created and then injected into FOO)
- blaze33 13y agoSeems like it's released under the Apache License 2.0 (cf. LICENSE file).
- _ZeD_ 13y agoPinject is a pythonic dependency injection library. + Implicit class bindings ...ummm...
- shadowmint 13y agosigh DI is not the same as an IOC container. Get it right ffs, if you want people to take you seriously. DI: class Blah(): def __init__(self, dependency): self.dep = depedency IOC: my_blah = container.resolve(Blah) Anyway, onto my main complaint: "Pinject is a pythonic dependency injection library. Python ports of other libraries, like Spring or Guice, retain the feel (and verbosity) of being designed for a statically typed language. Pinject was designed from the ground up for python." Wow, I'm impressed. Designed from the ground up for python. That's why you needed ~20 pages of documentation on how to use it? Intuitive. Also, what's wrong with annotations? I'm rather fond of this sort of code: ### implements, resolve, Scope class IType(object): prop1 = None def call(self): pass @implements(IType) class ImplType(object): prop1 = "Value" def call(self): pass scope = Scope() scope.register(ImplType) @resolve(scope) class UsesType(object): def __init__(self, t=IType): self.t = t instance = UsesType() Or in pinject: obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()]) needs_provider = obj_graph.provide(NeedsProvider) But wait, I want a test. Ok~ instance = UsesType(my_mock) Or in pinject: ?????? In fact, pinject doesn't even mention tests in its documentation. Whew~ That's only the whole reason for using DI in the first place. Self important library is self important. Not amazed.
- nbevans 13y ago"IOC: my_blah = container.resolve(Blah)" That's not IOC. That's service location. Which is only used at the "composition root" (look it up) in IOC. "In fact, pinject doesn't even mention tests in its documentation. Whew~ That's only the whole reason for using DI in the first place." No, testing accounts for just one of the more minor reasons to be using DI.
- shadowmint 13y agoI would argue the single greatest benefit (possibly, only benefit) that DI provides over other service location options (eg. factories) is that you get a nice means to test independent units of code by providing mock implementations. In dynamic languages with no real 'private' members, the benefit is actually pretty minimal because you can assign mock service instances after the object is created. eg. test_instance = Blah() test_instance.service = MockService() vs. test_instance = Blah(MockService()) ...which means, there isn't a lot of point in using it, unless you're using an IOC container which gives you some other synergy bonuses like singletons, per thread and per request instances, configuration file driven implementation binding, etc.
- nbevans 13y agoNo the single greatest benefit that a IOC container provides is object lifetime and scoping management. The next greatest benefit is the ability to decompose your code base into a single responsibility adhering components with good decoupling and namespace cohesion characteristics. Testing is very low down on the list of advantages of a IOC container. And even then, most people that think they're doing testing properly with a IOC container are doing it wrong. Hint: "Re-binding" your container by forcing it to drop an existing service implementation and replacing it with your mock/test implementation is "doing it wrong". The reason there is always so much discourse around DI and IOC is because very few programmers actually bothered to learn, and grok it, even if they think they already have.
- _pmf_ 13y ago
- deleted 13y ago[deleted]
- nailer 13y agoI don't get dependency injection. I come from languages that I am told don't have it. But when I read the Wikipedia page for DI, I get: "a dependent consumer a declaration of a component's dependencies, defined as interface contracts an injector (sometimes referred to as a provider or container) that creates instances of classes that implement a given dependency interface on request." Wait, I still have to declare dependencies, just like the import statement in python, require.js in JS, etc. which are apparently not 'dependency injection' systems? And this just adds, er more code? That same wikipedia page mentions dynamically loaded dependencies while also mentioning 'a declaration of a components dependencies' which sure doesn't sound dynamic to me. Does anyone care to provide a better explanation of what dependency injection gives me over the existing common dependency mechanisms?
- arethuza 13y agoIn a stackoverflow thread I found a reference to this classic: '"Dependency Injection" is a 25-dollar term for a 5-cent concept.' http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html http://www.jamesshore.com/Blog/Dependency-Injection-Demystif... I do think it is a useful concept - but I sometimes think it gets a bit blown out of proportion.
- JanezStupar 13y agoPython itself has DI built in throughout the stack. Building Java like DI mechanisms is cargo cultism. The whole point of DI in Java is to work around its static typedness, so one can perform runtime binding of components in a dynamic manner. Three quarters of cool Java and .NET "design patterns" are just band aids around semantic limitations of these languages.
- altcognito 13y ago> The whole point of DI in Java is to work around its static typedness. So, coding the configuration of your application is an ideal way to work. Interesting.
- JanezStupar 13y ago
- hosay123 13y agoThe author could refactor the documentation a little, starting with removal of the word "Pythonic" and perhaps ending only after 90% of the text has been replaced with a single section entitled "WHY GOD WHYYYYY". def python_di_copyright_2069_hosay123(dep, *args, **kwargs): modname, _, classname = dep.rpartition('.') mod = importlib.import_module(modname) return getattr(mod, classname)(*args, **kwargs) > Though Google owns this project's copyright, this project is not an official Google product. We just published it under Google's Github to give a terrible project implied legitimacy that it likely doesn't even have internally.
- sly010 13y agoI understand dependency injection, but I never understood dependency injection frameworks. For me the whole point of DI is explicit composability. There should only be a few well defined places in my application where all my classes are assembled into a working program. If my classes cover my domain nicely, I should be able to compose all kinds of programs (including tests) and reuse code. If my objects get injected to each other automatically by their name then my dependencies are just as predetermined, which results in coupled code, except the coupling is now difficult to read or modify. Once I decided I am only using explicit injection, I don't need a framework, I just instantiate my classes in the right order and pass them into each other. What can possibly be more pythonic than that? I have the same issue with Angular.js btw. They are trying to make is easy to start by adding dependency injection magic, but in reality all I see is "this can't possibly work (and indeed it doesn't)", so I just need to spend more time digging and understanding the magic before I can start writing ANY code. Every documentation should start by explaining the explicit way of doing things, then adding the sugar afterwards. import this
- lmm 13y agoI'd prefer by type to by name, but there's still a small decoupling advantage: suppose you have some componentA in your application and you want to add some more functionality that depends on some serviceB. What DI should make possible is you modify only componentA, to state that it now depends on serviceB, and as long as you have a serviceB available then you don't need to change your "wire up my application" code at all (but of course if there is no serviceB then this should fail as fast as possible and tell you to fix it). /has just written a compile-time DI framework in scala using type-level programming. It's pretty sweet except for the compile times.
- shawabawa3 13y ago> What DI should make possible is you modify only componentA, to state that it now depends on serviceB, and as long as you have a serviceB available then you don't need to change your "wire up my application" code at all So... instead of modifying just the "wire up my application" code, you modify just the componentA code. In return you get to fill your code with magic so nobody can see where serviceB is created.
- Uchikoma 13y agoDI is about breaking constructor coupling. I wish people would understand that.
- porker 13y agoDependency Injection (DI) and Dependency Injection Containers (DIC) are the "in-thing" in PHP at present, and to speak against them [0] is - like disagreeing with anything fanboys latch onto - ridiculed, without a sensible discussion or explanation. From a testing perspective I sort-of get it; from a "this is less tightly coupled" I don't: all you've done is move the coupling to a different level. Code always has to be coupled at some level, so where's the advantage? With the amount of noise about DI I'm sure it's something I should pay attention to rather than be turned off (as happened with Rails), but I really don't et it. Can anyone provide the missing piece in my thinking? [0] http://till.klampaeckel.de/blog/archives/154-Dependency-Injection-Containers.html http://till.klampaeckel.de/blog/archives/154-Dependency-Inje...
- chris_wot 13y agoActually, that is the point. If you decouple the objects via the container at the composition root, then you have actually achieved loose-coupling of objects.
- Lapsa 13y agoadvantage is when you manage to couple things at composition root (which is the very beginning of your application). that way there is one convenient place where coupling takes place. read "Dependency injection in .Net" by Mark Seemann. it's the best resource to understand wtf DI is all about and what are benefits.
- giulianob 13y agoYes even if you don't program .NET, the first half of the book is just about manual DI principles that could apply to almost any language. His blog also has good stuff about DI.
- PommeDeTerre 13y agoIt's interesting to follow the flow of ideas among languages/platforms. We've repeatedly seen concepts that were popularized by the enterprise Java crowd flow down to the .NET crowd, and eventually to the PHP crowd. IoC and DI is a good example of this. It was extremely hyped within the Java community during the early- and mid-2000s. Then this flowed into the C# community, with it getting a lot of attention during the late-2000s and early-2010s. Now it has finally made its way to the PHP community. An astute PHP user who recognizes this flow of ideas will look at how the trend has progressed within the Java and C# communities. What they'll see is that there has be movement away from IoC and DI. The purported advantages never materialized, but there was a lot of pain and bad code left around. Many in the Java community have moved on toward simpler frameworks and techniques, or even toward a far more static JVM-targeting language like Scala. Many C# users have similarly started moving away to other approaches. At some point, perhaps around 2016 or so, the PHP community will come to the same conclusions about the suitability (or lack thereof) of these techniques. After experiencing the problems first hand, they'll too move back to simpler, more explicit approaches.
- MostAwesomeDude 13y agoStop writing Java code in Python. No. Bad. Stop it.
- Myrmornis 13y agoImplicit class bindings sound like a really bad idea and hard to debug. Pinject creates implicit bindings for classes. The implicit bindings assume your code follows PEP8 conventions: your classes are named in CamelCase, and your args are named in lower_with_underscores. Pinject transforms class names to injectable arg names by lowercasing words and connecting them with underscores. It will also ignore any leading underscore on the class name. If two classes map to the same arg name, whether those classes are in the same module or different modules, Pinject will not create an implicit binding for that arg name (though it will not raise an error).