Set Python Guesthouse as “Starred⭐“ to receive the latest news first
Many beginners prefer to use global variables because they are easier to understand than passing parameters around functions. Indeed, using global variables is convenient in many scenarios. However, as the codebase grows and multiple files are involved, global variables can become quite chaotic. You may not know in which file a global variable of the same type or even with the same name is defined, nor how this variable is manipulated somewhere in the program.
Therefore, for such situations, there is a better implementation method: Singleton
The Singleton is a design pattern where a class using this pattern will only generate one instance.
The Singleton pattern ensures that in different parts of the program, you can only access the same object instance: if the instance does not exist, it will create one; if it already exists, it will return that instance. Since a singleton is a class, you can also provide corresponding operation methods for it to facilitate the management of this instance.
For example, if you are developing a game software, you need something like a “scene manager” to manage the switching of game scenes, resource loading, network connections, and other tasks. This manager needs to have various methods and properties, and it will be called in many places in the code, and the same manager must be called; otherwise, it can easily lead to conflicts and waste resources. In this case, the Singleton pattern is a very good implementation method.
The Singleton pattern is widely used in various development scenarios and is a must-know for developers. It is also a common question in many interviews. This article summarizes the mainstream methods for implementing the Singleton pattern for readers’ reference.
I hope that after reading this article, students can confidently tell the interviewer, “I know 5 implementations of the Singleton pattern, which one do you want to hear?”
Here is the index of implementation methods:
-
Implement Singleton using function decorators
-
Implement Singleton using class decorators
-
Implement Singleton using the __new__ keyword
-
Implement Singleton using metaclass
-
Module-level Singleton
1. Implement Singleton using function decorators
The implementation code is as follows:
def singleton(cls): _instance = {} def inner(): if cls not in _instance: _instance[cls] = cls() return _instance[cls] return inner
@singletonclass Cls(object): def __init__(self): pass
cls1 = Cls()cls2 = Cls()print(id(cls1) == id(cls2))
Output result:
True
In Python, the id keyword can be used to check the memory location of an object. Here, the id values of cls1 and cls2 are the same, indicating that they point to the same object.
For those who do not understand decorators, you can refer to the previous article 【Programming Class】 An Analysis of Decorators or use a search engine to learn it again. A clever point in the code is:
_instance = {}
Using an immutable class address as the key and its instance as the value, each time an instance is created, it first checks whether an instance of that class exists. If it exists, it directly returns that instance; otherwise, it creates a new instance and stores it in the dictionary.
2. Implement Singleton using class decorators
The code is as follows:
class Singleton(object): def __init__(self, cls): self._cls = cls self._instance = {} def __call__(self): if self._cls not in self._instance: self._instance[self._cls] = self._cls() return self._instance[self._cls]@Singletonclass Cls2(object): def __init__(self): pass
cls1 = Cls2()cls2 = Cls2()print(id(cls1) == id(cls2))
Also, since it is object-oriented, it can also be used like this:
class Cls3(): pass
Cls3 = Singleton(Cls3)
cls3 = Cls3()cls4 = Cls3()print(id(cls3) == id(cls4))
The principle of implementing Singleton using class decorators is similar to that of function decorators. Once you understand the previous section, understanding this should not be difficult.
3. Implement Singleton using the new keyword
Before discussing the other two methods, it is necessary to understand how a class and an instance are created in Python and the order of methods involved.
In simple terms, metaclasses can create a class through the method __metaclass__, and a class can create an instance through the method __new__.
In the application of the Singleton pattern, by controlling the process of creating a class or an instance, the goal of producing a single object can be achieved.
Using the __new__ method to intervene during instance creation achieves the purpose of implementing the Singleton pattern.
class Single(object): _instance = None def __new__(cls, *args, **kw): if cls._instance is None: cls._instance = object.__new__(cls, *args, **kw) return cls._instance def __init__(self): pass
single1 = Single()single2 = Single()print(id(single1) == id(single2))
Once you understand the application of __new__, understanding the Singleton pattern becomes easier. Here, we use
_instance = None
to store the instance. If _instance is None, a new instance is created; otherwise, the instance stored in _instance is returned directly.
4. Implement Singleton using metaclass
Similarly, we intervene during class creation to achieve the purpose of implementing Singleton.
Before implementing Singleton, it is necessary to understand how to create a class using type. The code is as follows:
def func(self): print("do sth")
Klass = type("Klass", (), {"func": func})
c = Klass()c.func()
Here, we used type to create a class, which is the basis for implementing Singleton with metaclass.
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls]class Cls4(metaclass=Singleton): pass
cls1 = Cls4()cls2 = Cls4()print(id(cls1) == id(cls2))
Here, we point the metaclass to the Singleton class, allowing the type in Singleton to create new Cls4 instances.
5. Module-level Singleton
In fact, in Python, a module itself is a singleton:
# my_singleton.pyimport random
class _Config: def __init__(self): self.num = random.random()
config = _Config() # Created when the module is imported
Using it in other code files:
from my_singleton import config
print(config.num) # The same value in all files
Since Python modules are loaded only once, they are naturally singletons. This is also the most Pythonic way, as seen in Flask’s current_app and app, which are created using this method.
Conclusion
This article discusses the Singleton pattern, but in the process of implementing the Singleton pattern, it involves many advanced Python syntax elements, including decorators, metaclasses, modules, new, type, and even super, etc. For beginners, it may be difficult to understand. In fact, in engineering projects, you do not need to master everything; mastering one method is sufficient, while the rest can be understood as background knowledge.
Previous Reviews
1. At a large company, a P9 with an annual salary of 3 million told me that leaders are most annoyed with such subordinates, even if their technology is excellent, they will not be given promotion opportunities~
2. What is the salary of iFlytek this year?
3. The 6 most commonly used API gateways in work
4. Another cloud storage "died", once called a conscience product by netizens
5. In 2025, these 9 Python GUI libraries will amaze me
Click to follow the public account for more exciting content