1. Introduction to Singleton Mode
-
Concept: The singleton pattern is a creational design pattern that ensures that a class has only one instance and provides a global access point to that instance.
-
Function: The main function of the singleton pattern is to ensure that only one instance exists in the application.
-
Advantage:
- Save system resources: Since only one instance exists, the system resource usage will be relatively small.
- Better control of global variables: The singleton pattern can effectively control the use of global variables, so as to better maintain the maintainability and scalability of the program.
- Better sharing of resources: Since only one instance exists, resources are better shared.
-
Disadvantages:
- The singleton pattern may cause code coupling: Since the singleton pattern can only create one instance, there may be excessive reliance on the singleton pattern in the program, which will lead to a high degree of code coupling.
- Singleton pattern may cause performance problems: If the instantiation process of the singleton pattern is complex, it may cause performance problems.
-
Application scenario:
- Log handler: In an application, only one log handler is needed to record all log information.
- Database connection pool: In the application, only one database connection pool is needed to manage all database connections.
- Global configuration information: In an application, only one instance of configuration information is required to manage all global configuration information.
In summary, the singleton pattern is suitable for those who need to ensure that only one instance exists in the application, and at the same time need to save system resources and have better control over global variables. But at the same time, we also need to pay attention to the code coupling and performance problems that may be caused by the singleton mode.
2. Implementation principle of singleton model
Implementation steps
The implementation principle of the Python singleton mode is basically the same as that of its programming language. The implementation steps are as follows:
- Define a class variable to store singleton instances
- In the initialization method, check whether the class variable has been assigned a value. If not, create a new instance and assign it to the class variable. If there is already an instance in the class variable, return that instance
- Provide a static method to return the singleton instance held in the class variable
Specifically, the implementation steps of the singleton mode are as follows:
class Singleton:
__instance = None
def __init__(self):
if Singleton.__instance is None:
Singleton.__instance = self
else:
raise Exception("Singleton class instantiated more than once")
@staticmethod
def get_instance():
if not Singleton.__instance:
Singleton()
return Singleton.__instance
In the above code, we define a class variable __instance to hold the singleton instance, and we __init__
check whether the instance already exists through the constructor. If it does not exist, a new instance is created. If it already exists, an exception is thrown, preventing multiple instances from being created.
We also implemented a static method get_instance
that returns the singleton instance held by the class variable __instance. When calling this method, we first check whether the class variable __instance exists, and if not, create a new instance. Otherwise, we just return the instance saved in the class variable __instance.
Here is an example using the above code:
s1 = Singleton.get_instance()
s2 = Singleton.get_instance()
assert s1 == s2 # s1 and s2 are equal
Since the Singleton pattern ensures that there is only one instance of a class, s1 and s2 should be equal. Since they are both the same instance, they should return True.
Introduction to static methods
@staticmethod
is a decorator in Python that indicates that the method is a static method. A static method is a class-related function that does not depend on any instance in the class, so a static method can be called without creating an instance of the class. Static methods can be used inside a class as well as outside it.
Static methods @staticmethod
are declared using decorators. For example:
class MyClass:
@staticmethod
def my_static_method():
print("This is a static method")
In the above code, we define a class MyClass and use @staticmethod
a decorator to declare the static method my_static_method(). In an instance of a class, we can call the method by:
my_instance = MyClass()
my_instance.my_static_method()
Alternatively, we can also call the method directly outside the class:
MyClass.my_static_method()
Note that, unlike other programming languages, static methods in Python can access class variables, but not instance variables.
@staticmethod
Is a decorator (decorator), used to declare a static method. A static method is a method that belongs to the class, not to an instance of the class. Using @staticmethod
a decorator allows methods to be invoked independently of any class instance.
Static methods can be called without instantiating the class. In a static method, you cannot access instance variables or instance methods in the class. If you need to access a property or method in a class, you should @classmethod
declare a class method with a decorator.
The main purpose of using static methods is to associate the method with the class, not with an instance of the class. Therefore, static methods are useful when you need to share methods between instances of a class.
Here is an @staticmethod
example using decorators:
class MyClass:
@staticmethod
def my_static_method():
print("This is a static method")
In the above code, we defined a MyClass
class named and @staticmethod
declared a my_static_method()
static method named using a decorator. We can share the method between instances of the class, or call the method directly outside the class.
my_instance = MyClass()
my_instance.my_static_method()
MyClass.my_static_method()
Output result:
This is a static method
This is a static method
methods shared between instances of a class
In Python, methods can be shared between instances of a class. This is because methods in Python are defined at the class level, not at the instance level. Therefore, all instances of this class share the same methods.
Here's an example where instances of two classes share a simple method:
class MyClass:
@staticmethod
def my_static_method():
print("This is a static method")
instance_1 = MyClass()
instance_2 = MyClass()
instance_1.my_static_method()
instance_2.my_static_method()
Output result:
This is a static method
This is a static method
In the above code, we defined a MyClass
class named and @staticmethod
declared a my_static_method()
static method named using a decorator. We create two MyClass
instances of , and share the method between them.
When we call this method on these two instances, we will find that they both print the same message, proving that the method is shared between these two instances.
3. Example
Realize the global configuration function
The singleton mode can be used to implement the global configuration information function to ensure that all modules in the application use the same configuration information to avoid conflicts and inconsistencies.
The following is a simple example to demonstrate how to use the singleton pattern to implement the global configuration information function:
class Config:
__instance = None
__config_data = {'key1': 'value1', 'key2': 'value2'}
def __new__(cls):
if cls.__instance is None:
cls.__instance = super().__new__(cls)
return cls.__instance
def get_config_value(self, key):
return self.__config_data.get(key)
def set_config_value(self, key, value):
self.__config_data[key] = value
config1 = Config()
config2 = Config()
# Set a new config value using config1
config1.set_config_value('key1', 'new_value1')
# Get the config value using config2
print(config2.get_config_value('key1'))
In the above code, we defined a Config
singleton class called and defined a static private variable in this class __instance
to ensure that an instance of this class is only created once. We also define a __config_data
private dictionary variable called to store global configuration information.
In the class definition, we use __new__()
the method to return the singleton instance. If the class already has an instance, subsequent calls to __new__()
the method will return that instance instead of creating a new one.
We also define two instance methods, get_config_value()
and set_config_value()
, for getting and setting configuration information.
In this example, we create two Config
instances of the class config1
and config2
. We first set the config1
with key1
, and then use config2
to get key1
the value of . We found that despite our config1
changes on the object, config2
the value obtained by the object is still value1
, proving that the two instances share the same global configuration information.
Realize the logging function
Suppose we have an application that needs to record logs, and we hope that there is only one log processor instance in the entire application, because multiple log processor instances will occupy system resources and cause the program to run slowly. At this point we can use the Python singleton pattern to ensure that there is only one log handler instance in the application.
The specific implementation is as follows:
class Logger:
instance = None
def __init__(self):
if not Logger.instance:
Logger.instance = self
else:
self.__dict__ = Logger.instance.__dict__
def log(self, message):
# 日志记录逻辑
pass
In the above code, we have used a class variable instance to hold the only instance of the Singleton class. Every time we create a Singleton object, we first check whether the class variable has been assigned. If not, create a new instance and assign it to the class variable. If there is already an instance in the class variable instance, that instance is returned. In this way, we ensure that only one Logger instance exists in the entire application.
Example using the above code:
logger1 = Logger()
logger2 = Logger()
assert logger1 == logger2
Since the Singleton pattern ensures that there is only one instance of a class, logger1 and logger2 should be equal. Since they are both the same instance, they should return True.
class MyClass:
@staticmethod # @staticmethod装饰器声明了一个名为my_static_method()的静态方法
def my_static_method():
print("This is a static method")
instance_1 = MyClass()
instance_2 = MyClass()
# 实例之间共享方法
# 实例1,2 共享了MyClass()类的my_static_method()方法
instance_1.my_static_method()
instance_2.my_static_method()
class Singleton:
__instance = None
def __init__(self):
if Singleton.__instance is None:
Singleton.__instance = self
else:
raise Exception("Singleton class instantiated more than once")
@staticmethod
def get_instance():
if not Singleton.__instance:
Singleton()
return Singleton.__instance
s1 = Singleton.get_instance()
s2 = Singleton.get_instance()
assert s1 == s2 # s1 and s2 are equal
class Logger:
instance = None
def __init__(self):
if not Logger.instance:
Logger.instance = self
else:
self.__dict__ = Logger.instance.__dict__
def log(self, message):
# 日志记录逻辑
# print(message)
return message
logger1 = Logger()
logger2 = Logger()
print(logger1.log("log1"))
print(logger2.log("log2"))
# assert logger1 == logger2
#********************* python 单例模式实现全局配置信息功能
class Config:
__instance = None
__config_data = {'key1': 'value1', 'key2': 'value2'}
def __new__(cls):
if cls.__instance is None:
cls.__instance = super().__new__(cls)
return cls.__instance
def get_config_value(self, key):
return self.__config_data.get(key)
def set_config_value(self, key, value):
self.__config_data[key] = value
config1 = Config()
config2 = Config()
print(config2.get_config_value('key1'))
# Set a new config value using config1
config1.set_config_value('key1', 'new_value1') # 设置已有信息
config1.set_config_value('key3', 'new_value3') # 新增信息
# Get the config value using config2
print(config2.get_config_value('key1'))
print(config2.get_config_value('key2'))
print(config2.get_config_value('key3'))
operation result:
This is a static method
This is a static method
log1
log2
value1
new_value1
value2
new_value3