Python Singletons
This blog is part of a series dedicated to the singleton pattern. In the Series page you can find all the posts of the series. |
- Introduction
- Singletons
- Class variable singleton
- Metaclass singleton
- Inheritance
- Program assignment or examples
- References
Introduction
Study pattern design for high-level languages like javascript or python is an uneasy exercise. This feeling originates in the intuition that there is a lot of these patterns that although necessary in C++, they seems to be almost invisible in language like python for example. I am not the only one having this intuition resulting in a series of discussions by very smart people about design pattern in high-level languages1.
Singletons
Singleton is one of those patterns that seems to be persistent amount all the different languages2. It is also a pattern that a lot of people dislike3, more on that in a moment. However, this pattern is one of those things that people expect you should know if you are working on anything related to coding or programming.
In this post, I would like to discuss singletons in python inspired by the following reference4. Singleton pattern can be defined as ensure a class only has one instance, and provide a global point of access it5. This definition although simple, I think it is too general keeping the pattern behavior a bit undefined. For example, as far I know, most of the issues with singletons arises when defining how they should behave at initialization time and when using inheritance.
I implemented, three types of singletons in python based on mostly reference 4, and I selected them because6:
- they are patterns that make instances from traditional classes behave like singleton object;
- they also have different behavior when initializing and when using inheritance.
Class variable singleton
Class variable singleton is one of the most common singleton implementations. The idea is to create a class that by inheritance make a user-defined class a singleton. I show an example of this pattern next.
The implementation relies on having a class variable named _intance and in redefining __new__() function in the parent ClassVariableSingleton. When the user initializes an instance of child class A, the call to __new__(…) is intercepted, creating a new instance if only if class variable _instance points to None. In this case, the function points _instance to the newly created instance and returns a reference to it. After this initialization, a reference to the first instance is always returned upon any other initialization of A.
One important thing to notice with this implementation is the global point to access the instance is done by reusing python syntax for object instantiation. However, this brings one issue: although every apparent instantiation returns the same instance, the constructor A.__init__(…) is executed against this instance before it is returned. We can say therefore that the instance is re-initialized every time we access it. Here it is a schematic example of the re-initialization:
This issue is regarded as undesirable because it is usually understood that instance should be initialized only once.
Note: this example can be run by executing ./ClassVariableSingleton.py I
from my repo as it shown below
Metaclass singleton
It is possible to avoid calling the constructor of the singleton more than once for the same instance and preserved in essence the previous pattern as shown in the following example.
This singleton implementation does not transfer the singleton feature by inheritance. Instead, it declares the user class as belonging to a singleton metaclass type that redefines the __call__(…) function. As a result, the first call to A(…) returns a new instance created calling the default __call__(…) that, in turn, it calls the constructor A.init(…). Calling A(…) for a second time returns the first instance without running its default __call__() and therefore avoiding re-initializing the instance again.
Note: this example can be run by executing ./MetaclassSingleton.py I
from my repo.
Inheritance
Inheritance works in the same way for both patterns describe above. So let’s assume I define a child class B of A, where A is a class-variable or a metaclass singleton
Do I get the same instance when calling B(…) than when calling A(…)? The answer to the questions is it depends on the order of the call.
If I instantiate the parent class A(…) first, both A and B will share the same value of the class variable _instance. Therefore, any call to B(…) will return the same as calling A(…) again, meaning B(…) will return the same instance as I show in next example.
Note: this example can be run by executing ./ClassVariableSingleton.py A
or ./MetaclassSingleton A
from my repo.
However, if I instantiate the child class B(…) first, the value of the class variable A._instance will be still None. Therefore, calling A(…) will return a new instance as represented in the following example.
Note: this example can be run by executing ./ClassVariableSingleton.py B
or ./MetaclassSingleton.py B
from my repo.
This issue is also seemed as very undesirable due to the fact singleton behavior depends on the order of when parent or child classes are instantiated. This could produce undefined program behavior if for example singleton parent and child are initialized on different threads.
In my next post I will show an alternative pattern that avoids instance re-initialization and it has a more consistent behavior when combine with inheritance.
Program assignment or examples
References
-
See, for example, this stack exchange entry. ↩
-
Design Patterns: Element of Reusable Object-Oriented Software. ↩
-
I you work with C++ I highly recommend chap 6 of Modern C++ design. ↩
Note of a interdiciplinarian by Victor E. Bazterra is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.