Factory provider ---------------- .. currentmodule:: dependency_injector.providers :py:class:`Factory` provider creates new objects. .. literalinclude:: ../../examples/providers/factory.py :language: python :lines: 3- The first argument of the ``Factory`` provider is a class, a factory function or a method that creates an object. The rest of the ``Factory`` positional and keyword arguments are the dependencies. ``Factory`` injects the dependencies every time when creates a new object. The dependencies are injected following these rules: + If the dependency is a provider, this provider is called and the result of the call is injected. + If you need to inject the provider itself, you should use the ``.provider`` attribute. More at :ref:`factory_providers_delegation`. + All other dependencies are injected *"as is"*. + Positional context arguments are appended after ``Factory`` positional dependencies. + Keyword context arguments have the priority over the ``Factory`` keyword dependencies with the same name. .. image:: images/factory_init_injections.png .. literalinclude:: ../../examples/providers/factory_init_injections.py :language: python :lines: 3- Passing arguments to the underlying providers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``Factory`` provider can pass the arguments to the underlying providers. This helps when you need to assemble a nested objects graph and pass the arguments deep inside. Consider the example: .. image:: images/factory_init_injections_underlying.png To create an ``Algorithm`` you need to provide all the dependencies: ``ClassificationTask``, ``Loss``, and ``Regularizer``. The last object in the chain, the ``Regularizer`` has a dependency on the ``alpha`` value. The ``alpha`` value varies from algorithm to algorithm: .. code-block:: python Algorithm( task=ClassificationTask( loss=Loss( regularizer=Regularizer( alpha=alpha, # <-- the dependency ), ), ), ) ``Factory`` provider helps to deal with the such assembly. You need to create the factories for all the classes and use special double-underscore ``__`` syntax for passing the ``alpha`` argument: .. literalinclude:: ../../examples/providers/factory_init_injections_underlying.py :language: python :lines: 3- :emphasize-lines: 24-35,39,42,45 When you use ``__`` separator in the name of the keyword argument the ``Factory`` looks for the dependency with the same name as the left part of the ``__`` expression. .. code-block:: __= If ```` is found the underlying provider will receive the ``=`` as an argument. .. _factory_providers_delegation: Passing providers to the objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When you need to inject the provider itself, but not the result of its call, use the ``.provider`` attribute of the provider that you're going to inject. .. image:: images/factory_delegation.png .. literalinclude:: ../../examples/providers/factory_delegation.py :language: python :lines: 3- :emphasize-lines: 25 .. note:: Any provider has a ``.provider`` attribute. Specializing the provided type ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can create a specialized ``Factory`` provider that provides only specific type. For doing this you need to create a subclass of the ``Factory`` provider and define the ``provided_type`` class attribute. .. literalinclude:: ../../examples/providers/factory_provided_type.py :language: python :lines: 3- :emphasize-lines: 12-14 Abstract factory ~~~~~~~~~~~~~~~~ :py:class:`AbstractFactory` provider helps when you need to create a provider of some base class and the particular implementation is not yet know. ``AbstractFactory`` provider is a ``Factory`` provider with two peculiarities: + Provides only objects of a specified type. + Must be overridden before usage. .. image:: images/abstract_factory.png :width: 100% :align: center .. literalinclude:: ../../examples/providers/abstract_factory.py :language: python :lines: 3- :emphasize-lines: 32 Factory aggregate providers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ :py:class:`FactoryAggregate` provider is a special type of provider that aggregates other :py:class:`Factory` providers. .. note:: :py:class:`FactoryAggregate` is not overridable. Calling of :py:meth:`FactoryAggregate.override` will result in raising of an exception. Next prototype might be the best demonstration of :py:class:`FactoryAggregate` features: .. literalinclude:: ../../examples/providers/factory_aggregate/prototype.py :language: python Example below shows one of the :py:class:`FactoryAggregate` use cases, when concrete implementation (game) must be selected based on dynamic input (CLI). Listing of ``games.py``: .. literalinclude:: ../../examples/providers/factory_aggregate/games.py :language: python Listing of ``example.py``: .. literalinclude:: ../../examples/providers/factory_aggregate/example.py :language: python .. disqus::