Singleton providers

Singleton provider creates new instance of specified class on first call and returns same instance on every next call.

Example:

../_images/singleton.png
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
"""`Singleton` providers example."""

import collections

import dependency_injector.providers as providers


UsersService = collections.namedtuple('UsersService', [])

# Singleton provider creates new instance of specified class on first call and
# returns same instance on every next call.
users_service_provider = providers.Singleton(UsersService)

# Retrieving several UserService objects:
users_service1 = users_service_provider()
users_service2 = users_service_provider()

# Making some asserts:
assert users_service1 is users_service2

Singleton providers resetting

Created and memorized by Singleton instance can be reset. Reset of Singleton‘s memorized instance is done by clearing reference to it. Further lifecycle of memorized instance is out of Singleton provider’s control and dependes on garbage collection strategy.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"""`Singleton` providers resetting example."""

import collections

import dependency_injector.providers as providers


UsersService = collections.namedtuple('UsersService', [])

# Users service singleton provider:
users_service_provider = providers.Singleton(UsersService)

# Retrieving several UsersService objects:
users_service1 = users_service_provider()
users_service2 = users_service_provider()

# Making some asserts:
assert users_service1 is users_service2

# Resetting of memorized instance:
users_service_provider.reset()

# Retrieving one more UserService object:
users_service3 = users_service_provider()

# Making some asserts:
assert users_service3 is not users_service1

Singleton providers and injections

Singleton provider has same interface as Factory provider, so, all of the rules about injections are the same, as for Factory provider.

Note

Due that Singleton provider creates specified class instance only on the first call, all injections are done once, during the first call. Every next call, while instance has been already created and memorized, no injections are done, Singleton provider just returns memorized earlier instance.

This may cause some problems, for example, in case of trying to bind Factory provider with Singleton provider (provided by dependent Factory instance will be injected only once, during the first call). Be aware that such behaviour was made with opened eyes and is not a bug.

By the way, in such case, Delegate or DelegatedSingleton provider can be useful . It makes possible to inject providers as is. Please check out Singleton providers delegation section.

Singleton providers delegation

Singleton provider could be delegated to any other provider via any kind of injection.

Delegation of Singleton providers is the same as Factory providers delegation, please follow Factory providers delegation section for examples (with exception of using DelegatedSingleton instead of DelegatedFactory).

Singleton providers specialization

Singleton provider could be specialized for any kind of needs via declaring its subclasses.

Specialization of Singleton providers is the same as Factory providers specialization, please follow Factory providers specialization section for examples.

Abstract singleton providers

AbstractSingleton provider is a Singleton provider that must be explicitly overridden before calling.

Behaviour of AbstractSingleton providers is the same as of AbstractFactory, please follow Abstract factory providers section for examples (with exception of using AbstractSingleton provider instead of AbstractFactory).

Singleton providers and multi-threading

Singleton provider is NOT thread-safe and should be used in multi-threading applications with manually controlled locking.

ThreadSafeSingleton is a thread-safe version of Singleton and could be used in multi-threading applications without any additional locking.

Also there could be a need to use thread-scoped singletons and there is a special provider for such case - ThreadLocalSingleton. ThreadLocalSingleton provider creates instance once for each thread and returns it on every call.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
"""`ThreadLocalSingleton` providers example."""

import threading
import Queue

import dependency_injector.providers as providers


def example(example_object, queue):
    """Put provided object in the provided queue."""
    queue.put(example_object)


# Create thread-local singleton provider for some object (main thread):
thread_local_object = providers.ThreadLocalSingleton(object)

# Create singleton provider for thread-safe queue:
queue = providers.Singleton(Queue.Queue)

# Create callable provider for example(), inject dependencies:
example = providers.DelegatedCallable(example,
                                      example_object=thread_local_object,
                                      queue=queue)

# Create factory provider for threads that are targeted to execute example():
thread_factory = providers.Factory(threading.Thread,
                                   target=example)

if __name__ == '__main__':
    # Create 10 threads for concurrent execution of example():
    threads = []
    for thread_number in range(10):
        threads.append(thread_factory(name='Thread{0}'.format(thread_number)))

    # Start execution of all created threads:
    for thread in threads:
        thread.start()

    # Wait while threads would complete their work:
    for thread in threads:
        thread.join()

    # Making some asserts (main thread):
    all_objects = set()

    while not queue().empty():
        all_objects.add(queue().get())

    assert len(all_objects) == len(threads)
    # Queue contains same number of objects as number of threads where
    # thread-local singleton provider was used.