design patterns - How to do dependency injection python-way? -
i've been reading lot python-way lately question is
how dependency injection python-way?
i talking usual scenarios when, example, service needs access userservice authorization checks.
it depends on situation. example, if use dependency injection testing purposes -- can mock out -- can forgo injection altogether: can instead mock out module or class otherwise inject:
subprocess.popen = some_mock_popen result = subprocess.call(...) assert some_mock_popen.result == result
subprocess.call()
call subprocess.popen()
, , can mock out without having inject dependency in special way. can replace subprocess.popen
directly. (this example; in real life in more robust way.)
if use dependency injection more complex situations, or when mocking whole modules or classes isn't appropriate (because, example, want mock out 1 particular call) using class attributes or module globals dependencies usual choice. example, considering my_subprocess.py
:
from subprocess import popen def my_call(...): return popen(...).communicate()
you can replace popen
call made my_call()
assigning my_subprocess.popen
; wouldn't affect other calls subprocess.popen
(but replace calls my_subprocess.popen
, of course.) similarly, class attributes:
class myclass(object): popen = staticmethod(subprocess.popen) def call(self): return self.popen(...).communicate(...)
when using class attributes this, necessary considering options, should take care use staticmethod
. if don't, , object you're inserting normal function object or type of descriptor, property, special when retrieved class or instance, wrong thing. worse, if used right now isn't descriptor (like subprocess.popen
class, in example) work now, if object in question changed normal function future, break confusingly.
lastly, there's plain callbacks; if want tie particular instance of class particular service, can pass service (or 1 or more of service's methods) class initializer, , have use that:
class myclass(object): def __init__(self, authenticate=none, authorize=none): if authenticate none: authenticate = default_authenticate if authorize none: authorize = default_authorize self.authenticate = authenticate self.authorize = authorize def request(self, user, password, action): self.authenticate(user, password) self.authorize(user, action) self._do_request(action) ... helper = authservice(...) # pass bound methods helper.authenticate , helper.authorize myclass. inst = myclass(authenticate=helper.authenticate, authorize=helper.authorize) inst.request(...)
when setting instance attributes that, never have worry descriptors firing, assigning functions (or classes or other callables or instances) fine.
Comments
Post a Comment