Add di_in_python page to the introduction

This commit is contained in:
Roman Mogilatov 2016-03-30 17:10:43 +03:00
parent 4e00a70834
commit 8444d7d1d5
8 changed files with 142 additions and 22 deletions

View File

@ -1,10 +1,88 @@
Dependency Injection in Python
------------------------------
Dependency injection and inversion of control in Python
-------------------------------------------------------
Interesting but, dependency injection is not very popular topic in Python.
The things are so because Python is an awesome language. Your eyes are opened
and your hands are free while you are using Python. In practice this means that
you can do dependency injection in Python in quite an easy way because language
itself helps you to do this. At the same time, even the thins are so, you still
have to do some work. Another one 'minor' problem is that there are several
ways to do dependency injection container.
Originally, dependency injection pattern got popular in languages with static
typing, like Java. Dependency injection framework can
significantly improve flexibility of the language with static typing. Also,
implementation of dependency injection framework for language with static
typing is not something that one can do shortly, it could be quite complex
thing to be done well.
While Python is very flexible interpreted language with dynamic typing, there
is a meaning that dependency injection doesn't work for it as well, as it does
for Java. Also there is a meaning that dependency injection framework is
something that Python developer would not ever need, cause dependency injection
could be implemented easily using language fundamentals.
It is true.
Partly.
Dependency injection, as a software design pattern, has number of
advantages that are common for each language (including Python):
+ Dependency Injection decreases coupling between a class and its dependency.
+ Because dependency injection doesn't require any change in code behavior it
can be applied to legacy code as a refactoring. The result is clients that
are more independent and that are easier to unit test in isolation using
stubs or mock objects that simulate other objects not under test. This ease
of testing is often the first benefit noticed when using dependency
injection.
+ Dependency injection can be used to externalize a system's configuration
details into configuration files allowing the system to be reconfigured
without recompilation (rebuilding). Separate configurations can be written
for different situations that require different implementations of
components. This includes, but is not limited to, testing.
+ Reduction of boilerplate code in the application objects since all work to
initialize or set up dependencies is handled by a provider component.
+ Dependency injection allows a client to remove all knowledge of a concrete
implementation that it needs to use. This helps isolate the client from the
impact of design changes and defects. It promotes reusability, testability
and maintainability.
+ Dependency injection allows a client the flexibility of being configurable.
Only the client's behavior is fixed. The client may act on anything that
supports the intrinsic interface the client expects.
.. note::
While improved testability is one the first benefits of using dependency
injection, it could be easily overwhelmed by monkey-patching technique,
that works absolutely great in Python (you can monkey-patch anything,
anytime). At the same time, monkey-patching has nothing similar with
other advantages defined above. Also monkey-patching technique is
something that could be considered like too dirty to be used in production.
The complexity of dependency injection pattern implementation in Python is
definitely quite lower than in other languages (even with dynamic typing).
.. note::
Low complexity of dependency injection pattern implementation in Python
still means that some code should be written, reviewed, tested and
supported.
Talking about inversion of control, it is a software design principle that
also works for each programming language, not dependending on its typing type.
Inversion of control is used to increase modularity of the program and make
it extensible.
Main design purposes of using inversion of control are:
+ To decouple the execution of a task from implementation.
+ To focus a module on the task it is designed for.
+ To free modules from assumptions about how other systems do what they do and
instead rely on contracts.
+ To prevent side effects when replacing a module.
Let's go through next example:
.. literalinclude:: ../../../examples/ioc_demo/car_engine_1.py
:language: python
``Car`` **creates** an ``Engine`` during its creation. Really? Does it make
more sense then creating an ``Engine`` separatelly and then
**put (inject) it into** ``Car`` when ``Car`` is being created?
.. literalinclude:: ../../../examples/ioc_demo/car_engine_2.py
:language: python

View File

@ -1,12 +1,14 @@
Introduction
============
Before you have started with *Dependency Injector* framework and dependecy
injection, there are a couple of introduction notes that might be useful.
Current section of documentation is designed to give some overview about
dependency injection pattern, inversion of control principle and
*Dependency Injector* framework.
.. toctree::
:maxdepth: 2
what_is_di
di_in_python
key_features
structure

View File

@ -0,0 +1,2 @@
Key features of Dependency Injector
-----------------------------------

View File

@ -0,0 +1,2 @@
Structure of Dependency Injector
--------------------------------

View File

@ -1,15 +1,15 @@
What is Dependency Injection?
-----------------------------
What is dependency injection and inversion of control?
------------------------------------------------------
Definition
~~~~~~~~~~
Wikipedia provides quite good definitions of Dependency Injection Pattern
Wikipedia provides quite good definitions of dependency injection pattern
and related principles:
.. glossary::
`Dependency Injection`_
`Dependency injection`_
In software engineering, dependency injection is a software design
pattern that implements inversion of control for resolving
dependencies. A dependency is an object that can be used (a service).
@ -31,7 +31,7 @@ and related principles:
services because these define how the client may use the services.
This separates the responsibilities of use and construction.
`Inversion of Control`_
`Inversion of control`_
In software engineering, inversion of control (IoC) describes a design
in which custom-written portions of a computer program receive the
flow of control from a generic, reusable library. A software
@ -51,7 +51,7 @@ and related principles:
principle, which concerns itself with decoupling dependencies between
high-level and low-level layers through shared abstractions.
`Dependency Inversion`_
`Dependency inversion`_
In object-oriented programming, the dependency inversion principle
refers to a specific form of decoupling software modules. When
following this principle, the conventional dependency relationships
@ -121,9 +121,9 @@ And `John Munsch`_ provided absolutely Great answer:
down to eat.
.. _Dependency Injection: http://en.wikipedia.org/wiki/Dependency_injection
.. _Inversion of Control: https://en.wikipedia.org/wiki/Inversion_of_control
.. _Dependency Inversion: https://en.wikipedia.org/wiki/Dependency_inversion_principle
.. _Dependency injection: http://en.wikipedia.org/wiki/Dependency_injection
.. _Inversion of control: https://en.wikipedia.org/wiki/Inversion_of_control
.. _Dependency inversion: https://en.wikipedia.org/wiki/Dependency_inversion_principle
.. _StackOverflow: http://stackoverflow.com/
.. _question: http://stackoverflow.com/questions/1638919/how-to-explain-dependency-injection-to-a-5-year-old/1639186
.. _user198313: http://stackoverflow.com/users/198313/user198313

View File

@ -1,4 +1,4 @@
"""The Code, that follows Inversion of Control principle."""
"""The Code, that follows inversion of control principle."""
class Service(object):

View File

@ -0,0 +1,18 @@
"""Car & Engine example 1."""
class Engine(object):
"""Example engine."""
class Car(object):
"""Example car."""
def __init__(self):
"""Initializer."""
self.engine = Engine()
if __name__ == '__main__':
car = Car()
assert car.engine is not None

View File

@ -0,0 +1,18 @@
"""Car & Engine example 2."""
class Engine(object):
"""Example engine."""
class Car(object):
"""Example car."""
def __init__(self, engine):
"""Initializer."""
self.engine = engine
if __name__ == '__main__':
car = Car(Engine())
assert car.engine is not None