Introduction and use of Python singleton mode

 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:

    1. Save system resources: Since only one instance exists, the system resource usage will be relatively small.
    2. 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.
    3. Better sharing of resources: Since only one instance exists, resources are better shared.
  • Disadvantages:

    1. 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.
    2. Singleton pattern may cause performance problems: If the instantiation process of the singleton pattern is complex, it may cause performance problems.
  • Application scenario:

    1. Log handler: In an application, only one log handler is needed to record all log information.
    2. Database connection pool: In the application, only one database connection pool is needed to manage all database connections.
    3. 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:

  1. Define a class variable to store singleton instances
  2. 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
  3. 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_instancethat 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

@staticmethodis 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 @staticmethodare 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 @staticmethoda 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.

@staticmethodIs 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 @staticmethoda 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 @classmethoddeclare 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 @staticmethodexample using decorators:

class MyClass:
    @staticmethod
    def my_static_method():
        print("This is a static method")

In the above code, we defined a MyClassclass named and @staticmethoddeclared 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 MyClassclass named and @staticmethoddeclared a my_static_method()static method named using a decorator. We create two MyClassinstances 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 Configsingleton class called and defined a static private variable in this class __instanceto ensure that an instance of this class is only created once. We also define a __config_dataprivate 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 Configinstances of the class config1and config2. We first set the config1with key1, and then use config2to get key1the value of . We found that despite our config1changes on the object, config2the 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

Guess you like

Origin blog.csdn.net/songpeiying/article/details/131857802