Suppose I have a loop (in Python syntax):

xml = "<x>...</x>"
for i in arr:
    j = f(x)  # some complex computation
    obj = Class(i, j)
    xml = obj.run(xml)

Does it make sense to use dependency injection for Class in this situation? If yes, what is the proper way to use DI in this context? Please provide an example.

Maybe I should replace Class with a factory creating this class?

Or should I not use dependency injection in this situation but leave Class(i, j) as is?

  • What's the purpose of the Class in the big(er) scheme of things? What happens during run? And what happens after run()? Knowing these things might give us a better idea whether or not dependency injection would make sense here. – Nick Alexeev Nov 24 '18 at 19:20
  • @NickAlexeev Class.run() runs a tranformation of XML->XML which is dependent on Class() arguments – porton Nov 24 '18 at 19:32
  • 1
    I see from the real code that the sample is part of a method; this context should be reflected in the sample, as it has consequences based on the injection surface (constructor arguments, setter, method arguments). It leads to one question in particular: is Class reusable? – outis Nov 24 '18 at 20:49
  • 1
    OK. What is the problem you're trying to solve with the IoC container? – Robert Harvey Nov 24 '18 at 21:28
  • 2
    You don't need an IoC container to do that. – Robert Harvey Nov 24 '18 at 22:02

Likely, you really don't need any dependency injection here. But if you do, then simply injecting via a function parameter is the simplest way to go in Python. Remember: in Python, all variables incl. class names are resolved at run time, so you can pass class objects around as ordinary variables. For example:

def transform_the_xml(xml, arr, StepClass=DefaultClass):
    for i in arr:
        j = f(x)  # some complex computation
        obj = StepClass(i, j)
        xml = obj.run(xml)

Alternatively, you could “inject” a factory function that creates an object, but that doesn't look differently from the above case (you'd only use a different naming convention for the argument).

Note that an object with a single method is just a complicated way to write a function. We could equivalently write:

def transform_the_xml(xml, arr, step=None):

    if step is None:
        def step(i, j, xml):
            return DefaultClass(i, j).run(xml)

    for i in arr:
        j = f(x)  # some complex computation
        xml = step(i, j, xml)

Then, you can easily inject whatever step implementation you want during unit testing.

  • 1
    "Note that an object with a single method is just a complicated way to write a function." Actually that would be a complicated way to write a closure. It only degenerates to a "complicated way to write a function" when it has a single method and it has no state setting constructors. – candied_orange Nov 24 '18 at 23:02

It definitely makes sense (think unit tests, among other reasons). The counterargument would be exposing the dependency can expose implementation details. Exposure can be mitigated by providing a sensible default (set default field values within constructors, or default arguments to methods/functions, depending on language capabilities; fortunately, with Python you can do either).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.