mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-07 07:00:49 +03:00
Update introduction docs
This commit is contained in:
parent
064a1653fd
commit
08b00d71d4
|
@ -1,4 +1,3 @@
|
|||
=============================================================
|
||||
Dependency Injector --- Python dependency injection framework
|
||||
=============================================================
|
||||
|
||||
|
@ -14,7 +13,7 @@ Dependency Injector --- Python dependency injection framework
|
|||
designed to be unified, developer's friendly tool for managing any kind
|
||||
of Python objects and their dependencies in formal, pretty way.
|
||||
|
||||
Below is a list of some key features and points of *Dependency Injector*:
|
||||
Key features of *Dependency Injector*:
|
||||
|
||||
- Easy, smart, pythonic style.
|
||||
- Obvious, clear structure.
|
||||
|
@ -22,8 +21,6 @@ Below is a list of some key features and points of *Dependency Injector*:
|
|||
- Thread safety.
|
||||
- Semantic versioning.
|
||||
|
||||
Main idea of *Dependency Injector* is to keep dependencies under control.
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
|
@ -59,7 +56,7 @@ Contents
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
main/introduction
|
||||
main/introduction/index
|
||||
main/installation
|
||||
providers/index
|
||||
catalogs/index
|
||||
|
@ -67,4 +64,3 @@ Contents
|
|||
api/index
|
||||
main/feedback
|
||||
main/changelog
|
||||
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
Introduction
|
||||
============
|
||||
|
||||
Before you have started with *Dependency Injector* framework and dependecy
|
||||
injection, there are a couple of introduction notes that might be useful.
|
||||
|
||||
What is DI and why is it needed?
|
||||
--------------------------------
|
||||
|
||||
Python ecosystem consists of a big amount of various libraries that contain
|
||||
different classes and functions that could be used for applications
|
||||
development. Each of them has its own role.
|
||||
|
||||
Modern Python applications are mostly the composition of well-known open
|
||||
source systems / frameworks / libraries and some turnkey functionality.
|
||||
|
||||
When application goes bigger, its complexity and SLOC_ are also increased.
|
||||
Being driven by SOLID_ (for example), developers often start to split
|
||||
application's sources into not so big classes, functions and modules, that are
|
||||
less complex, could be reused several times and so on... It always helps, but
|
||||
there is another problem on the horizon.
|
||||
|
||||
The name of this problem is - "Dependency hell!". It sounds like "I have so
|
||||
many classes and functions! They are great, now I can understand each of them,
|
||||
but it is so hard to see the whole picture! How are they linked with each
|
||||
other? What dependencies does this class have?". And this is a key question:
|
||||
"What dependencies does certain class / function have?". To resolve this issues
|
||||
developers have to go inside with IoC_ principles and implementation patterns.
|
||||
|
||||
One of such IoC_ implementation patterns is called `dependency injection`_.
|
||||
|
||||
Dependency injection 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.
|
||||
|
||||
Key features
|
||||
------------
|
||||
|
||||
*Dependency Injector* is a dependency injection framework for Python projects.
|
||||
It was designed to be unified, developer's friendly tool for managing any kind
|
||||
of Python objects and their dependencies in formal, pretty way.
|
||||
|
||||
Below is a list of some key features and points of *Dependency Injector*
|
||||
framework:
|
||||
|
||||
- Easy, smart, pythonic style.
|
||||
- Obvious, clear structure.
|
||||
- Memory efficiency.
|
||||
- Semantic versioning.
|
||||
|
||||
Main idea of *Dependency Injector* is to keep dependencies under control.
|
||||
|
||||
Main entities
|
||||
-------------
|
||||
|
||||
Current section describes *Dependency Injector* main entities and their
|
||||
interaction with each other.
|
||||
|
||||
.. image:: /images/internals.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
There are 3 main entities:
|
||||
|
||||
- Providers. Providers are strategies of accesing objects. For example,
|
||||
:py:class:`dependency_injector.providers.Factory` creates new instance of
|
||||
provided class every time it is called.
|
||||
:py:class:`dependency_injector.providers.Singleton` creates provided
|
||||
instance once and returns it on every next call. Providers could be
|
||||
overridden by another providers. Base class is -
|
||||
:py:class:`dependency_injector.providers.Provider`.
|
||||
- Injections. Injections are instructions for making dependency injections
|
||||
(there are several ways how they could be done). Injections are used mostly
|
||||
by :py:class:`dependency_injector.providers.Factory` and
|
||||
:py:class:`dependency_injector.providers.Singleton` providers, but
|
||||
these are not only cases. Base class is -
|
||||
:py:class:`dependency_injector.injections.Injection`.
|
||||
- Catalogs. Catalogs are collections of providers. They are used for grouping
|
||||
of providers by some principles. Base class is -
|
||||
:py:class:`dependency_injector.catalogs.DeclarativeCatalog`.
|
||||
|
||||
|
||||
.. _SLOC: http://en.wikipedia.org/wiki/Source_lines_of_code
|
||||
.. _SOLID: http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29
|
||||
.. _IoC: http://en.wikipedia.org/wiki/Inversion_of_control
|
||||
.. _dependency injection: http://en.wikipedia.org/wiki/Dependency_injection
|
10
docs/main/introduction/di_in_python.rst
Normal file
10
docs/main/introduction/di_in_python.rst
Normal file
|
@ -0,0 +1,10 @@
|
|||
Dependency Injection 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.
|
12
docs/main/introduction/index.rst
Normal file
12
docs/main/introduction/index.rst
Normal file
|
@ -0,0 +1,12 @@
|
|||
Introduction
|
||||
============
|
||||
|
||||
Before you have started with *Dependency Injector* framework and dependecy
|
||||
injection, there are a couple of introduction notes that might be useful.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
what_is_di
|
||||
di_in_python
|
45
docs/main/introduction/introduction_.rst
Normal file
45
docs/main/introduction/introduction_.rst
Normal file
|
@ -0,0 +1,45 @@
|
|||
Key features
|
||||
------------
|
||||
|
||||
*Dependency Injector* is a dependency injection framework for Python projects.
|
||||
It was designed to be unified, developer's friendly tool for managing any kind
|
||||
of Python objects and their dependencies in formal, pretty way.
|
||||
|
||||
Below is a list of some key features and points of *Dependency Injector*
|
||||
framework:
|
||||
|
||||
- Easy, smart, pythonic style.
|
||||
- Obvious, clear structure.
|
||||
- Memory efficiency.
|
||||
- Semantic versioning.
|
||||
|
||||
Main idea of *Dependency Injector* is to keep dependencies under control.
|
||||
|
||||
Main entities
|
||||
-------------
|
||||
|
||||
Current section describes *Dependency Injector* main entities and their
|
||||
interaction with each other.
|
||||
|
||||
.. image:: /images/internals.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
There are 3 main entities:
|
||||
|
||||
- Providers. Providers are strategies of accesing objects. For example,
|
||||
:py:class:`dependency_injector.providers.Factory` creates new instance of
|
||||
provided class every time it is called.
|
||||
:py:class:`dependency_injector.providers.Singleton` creates provided
|
||||
instance once and returns it on every next call. Providers could be
|
||||
overridden by another providers. Base class is -
|
||||
:py:class:`dependency_injector.providers.Provider`.
|
||||
- Injections. Injections are instructions for making dependency injections
|
||||
(there are several ways how they could be done). Injections are used mostly
|
||||
by :py:class:`dependency_injector.providers.Factory` and
|
||||
:py:class:`dependency_injector.providers.Singleton` providers, but
|
||||
these are not only cases. Base class is -
|
||||
:py:class:`dependency_injector.injections.Injection`.
|
||||
- Catalogs. Catalogs are collections of providers. They are used for grouping
|
||||
of providers by some principles. Base class is -
|
||||
:py:class:`dependency_injector.catalogs.DeclarativeCatalog`.
|
130
docs/main/introduction/what_is_di.rst
Normal file
130
docs/main/introduction/what_is_di.rst
Normal file
|
@ -0,0 +1,130 @@
|
|||
What is Dependency Injection?
|
||||
-----------------------------
|
||||
|
||||
Definition
|
||||
~~~~~~~~~~
|
||||
|
||||
Wikipedia provides quite good definitions of Dependency Injection Pattern
|
||||
and related principles:
|
||||
|
||||
.. glossary::
|
||||
|
||||
`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).
|
||||
An injection is the passing of a dependency to a dependent object (a
|
||||
client) that would use it. The service is made part of the client's
|
||||
state. Passing the service to the client, rather than allowing a
|
||||
client to build or find the service, is the fundamental requirement of
|
||||
the pattern.
|
||||
|
||||
Dependency injection allows a program design to follow the dependency
|
||||
inversion principle. The client delegates to external code (the
|
||||
injector) the responsibility of providing its dependencies. The client
|
||||
is not allowed to call the injector code. It is the injecting code
|
||||
that constructs the services and calls the client to inject them. This
|
||||
means the client code does not need to know about the injecting code.
|
||||
The client does not need to know how to construct the services. The
|
||||
client does not need to know which actual services it is using. The
|
||||
client only needs to know about the intrinsic interfaces of the
|
||||
services because these define how the client may use the services.
|
||||
This separates the responsibilities of use and construction.
|
||||
|
||||
`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
|
||||
architecture with this design inverts control as compared to
|
||||
traditional procedural programming: in traditional programming, the
|
||||
custom code that expresses the purpose of the program calls into
|
||||
reusable libraries to take care of generic tasks, but with inversion
|
||||
of control, it is the reusable code that calls into the custom, or
|
||||
task-specific, code.
|
||||
|
||||
Inversion of control is used to increase modularity of the program and
|
||||
make it extensible, and has applications in object-oriented
|
||||
programming and other programming paradigms. The term was popularized
|
||||
by Robert C. Martin and Martin Fowler.
|
||||
|
||||
The term is related to, but different from, the dependency inversion
|
||||
principle, which concerns itself with decoupling dependencies between
|
||||
high-level and low-level layers through shared abstractions.
|
||||
|
||||
`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
|
||||
established from high-level, policy-setting modules to low-level,
|
||||
dependency modules are reversed, thus rendering high-level modules
|
||||
independent of the low-level module implementation details. The
|
||||
principle states:
|
||||
|
||||
+ High-level modules should not depend on low-level modules.
|
||||
Both should depend on abstractions.
|
||||
+ Abstractions should not depend on details.
|
||||
Details should depend on abstractions.
|
||||
|
||||
The principle inverts the way some people may think about
|
||||
object-oriented design, dictating that both high- and low-level
|
||||
objects must depend on the same abstraction.
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Let's go through the code of ``example.py``:
|
||||
|
||||
.. literalinclude:: ../../../examples/di_demo/example.py
|
||||
:language: python
|
||||
|
||||
At some point, things defined above mean, that the code from ``example.py``,
|
||||
could look different, like in ``ioc_example.py``:
|
||||
|
||||
.. literalinclude:: ../../../examples/di_demo/ioc_example.py
|
||||
:language: python
|
||||
|
||||
Also the code from ``ioc_example.py`` could be powered by dependency
|
||||
injection framework, like in ``di_example.py``:
|
||||
|
||||
.. literalinclude:: ../../../examples/di_demo/di_example.py
|
||||
:language: python
|
||||
|
||||
.. note::
|
||||
|
||||
``Components`` from ``di_example.py`` is an IoC container. It contains a
|
||||
collection of component providers that could be injected into each other.
|
||||
|
||||
Assuming this, ``Components`` could be one and the only place, where
|
||||
application's structure is being managed on the high level.
|
||||
|
||||
Best explanation, ever
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Some times ago `user198313`_ posted awesome `question`_ about dependency
|
||||
injection on `StackOverflow`_:
|
||||
|
||||
.. note::
|
||||
|
||||
How to explain dependency injection to a 5-year-old?
|
||||
|
||||
And `John Munsch`_ provided absolutely Great answer:
|
||||
|
||||
.. note::
|
||||
|
||||
When you go and get things out of the refrigerator for yourself, you can
|
||||
cause problems. You might leave the door open, you might get something
|
||||
Mommy or Daddy doesn't want you to have. You might even be looking for
|
||||
something we don't even have or which has expired.
|
||||
|
||||
What you should be doing is stating a need, "I need something to drink
|
||||
with lunch," and then we will make sure you have something when you sit
|
||||
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
|
||||
.. _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
|
||||
.. _John Munsch: http://stackoverflow.com/users/31899/john-munsch
|
20
examples/di_demo/di_example.py
Normal file
20
examples/di_demo/di_example.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
"""The Code, powered by Dependency Injector."""
|
||||
|
||||
from dependency_injector import catalogs, providers
|
||||
from ioc_example import Service, Client
|
||||
|
||||
|
||||
class Components(catalogs.DeclarativeCatalog):
|
||||
"""Components catalog."""
|
||||
|
||||
service = providers.Factory(Service)
|
||||
""":type: providers.Factory -> Service"""
|
||||
|
||||
client = providers.Factory(Client,
|
||||
service=service)
|
||||
""":type: providers.Factory -> Client"""
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Application creates Client's instance using its provider
|
||||
client = Components.client() # equivalent of Client(service=Service())
|
18
examples/di_demo/example.py
Normal file
18
examples/di_demo/example.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
"""The Code."""
|
||||
|
||||
|
||||
class Service(object):
|
||||
"""Some "Service"."""
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""Some "Client" that uses "Service"."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initializer."""
|
||||
self.service = Service() # Service instance is created inside Client
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Application just creates Client's instance
|
||||
client = Client()
|
21
examples/di_demo/ioc_example.py
Normal file
21
examples/di_demo/ioc_example.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
"""The Code, that follows Inversion of Control principle."""
|
||||
|
||||
|
||||
class Service(object):
|
||||
"""Some "Service"."""
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""Some "Client" that uses "Service"."""
|
||||
|
||||
def __init__(self, service): # Service instance is injected in Client
|
||||
"""Initializer."""
|
||||
self.service = service
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Application creates Service instance
|
||||
service = Service()
|
||||
|
||||
# and inject Service instance into the Client
|
||||
client = Client(service)
|
Loading…
Reference in New Issue
Block a user