.. 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.
.. literalinclude:: ../../examples/providers/factory_init_injections.py :language: python :lines: 3-
Factory
provider can inject attributes. Use .add_attributes()
method to specify
attribute injections.
.. literalinclude:: ../../examples/providers/factory_attribute_injections.py :language: python :lines: 3- :emphasize-lines: 18-18
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:
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:
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: 44,49
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.
<dependency>__<keyword for the underlying provider>=<value>
If <dependency>
is found the underlying provider will receive the
<keyword for the underlying provider>=<value>
as an argument.
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.
.. literalinclude:: ../../examples/providers/factory_delegation.py :language: python :lines: 3- :emphasize-lines: 28
Note
Any provider has a .provider
attribute.
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
: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.
.. literalinclude:: ../../examples/providers/abstract_factory.py :language: python :lines: 3- :emphasize-lines: 34
:py:class:`FactoryAggregate` provider aggregates multiple factories.
.. seealso:: :ref:`aggregate-provider` – it's a successor of ``FactoryAggregate`` provider that can aggregate any type of provider, not only ``Factory``.
The aggregated factories are associated with the string keys. When you call the
FactoryAggregate
you have to provide one of the these keys as a first argument.
FactoryAggregate
looks for the factory with a matching key and calls it with the rest of the arguments.
.. literalinclude:: ../../examples/providers/factory_aggregate.py :language: python :lines: 3- :emphasize-lines: 33-37,47
You can get a dictionary of the aggregated providers using .providers
attribute.
To get a game provider dictionary from the previous example you can use
game_factory.providers
attribute.
You can also access an aggregated factory as an attribute. To create the Chess
object from the
previous example you can do chess = game_factory.chess("John", "Jane")
.
Note
You can not override the FactoryAggregate
provider.
Note
When you inject the FactoryAggregate
provider it is passed "as is".
To use non-string keys or string keys with .
and -
, you can provide a dictionary as a positional argument:
providers.FactoryAggregate({
SomeClass: providers.Factory(...),
"key.with.periods": providers.Factory(...),
"key-with-dashes": providers.Factory(...),
})
Example:
.. literalinclude:: ../../examples/providers/factory_aggregate_non_string_keys.py :language: python :lines: 3- :emphasize-lines: 30-33,39-40
.. disqus::