Python Object-Oriented Singleton Model

Keywords: Python Attribute

Singleton Design Patterns

Design pattern

  • Design pattern is the summary and refinement of previous work. Usually, the design pattern widely circulated by people is a mature solution to a particular problem.
  • Design patterns are used to reuse code, make it easier for others to understand, and ensure the reliability of code.

Singleton mode

  • Purpose - Let the object created by the class have only one instance in the system.
  • The memory address of the object returned by the class name () is the same for each execution.

_ new_ Method

_ new_ action
When using class name () to create an object, the python interpreter first calls the _new_ method to allocate memory space for the object.
_ new_ is a built-in static method provided by the object base class.

There are two main functions:

  • Allocate space for objects in memory;
  • Returns a reference to the object;

After the python interpreter obtains the object's reference, it passes the reference as the first parameter to the _init__method.

Rewrite _new_ method note

The code for rewriting the _new_ method is very fixed.
Rewrite _new_ method must return super (). _new_ (cls);
Otherwise, the python interpreter will not invoke the initialization method of the object without the reference of the object allocated space.
Note that _new_ is a static method that needs to pass cls parameters on its own initiative when invoked.

Rewrite the new method example

class MusicPlayer(object):
    def __new__(cls, *args, **kwargs):
        # 1. When an object is created, the new method is automatically called
        print("__new__Method, create objects, allocate space")
        # 2. Allocate memory space for objects
        instance = super().__new__(cls)
        # 3. References to returned objects
        return instance

    def __init__(self):
        print("__init__, Player initialization")


palyer = MusicPlayer()

print(palyer)

# _ new_ method, create objects, allocate space
# _ init_, player initialization
# <__main__.MusicPlayer object at 0x00000136237A92E8>

If the new method does not return super (). new (cls), subsequent initialization methods cannot be performed.

class MusicPlayer(object):
    def __new__(cls, *args, **kwargs):
        # 1. When an object is created, the new method is automatically called
        print("__new__Method, create objects, allocate space")

    def __init__(self):
        print("__init__, Player initialization")


palyer = MusicPlayer()

print(palyer)

# _ new_ method, create objects, allocate space
# None

Singleton in Python

Single case

Singleton -- Let the class create an object that has only one instance in the system;
1. Define a class attribute with an initial value of None, which is used to record references to singleton objects.
2. Rewriting _new_ Method
3. If the class attribute is None, use super() to call the parent class method to allocate space and record the results in the class attribute.
4. Return object references recorded in class attributes;

Idea Analysis of Single Case Design Model

First, set a class attribute with an initial value of None.
Override the new method. If the class attribute is None, it means that the object is created for the first time, then the memory address returned by the new method when creating the object is passed to the class attribute.
When the object is created later, the class attribute is no longer None. In the new method, the value of the class attribute is returned directly, so that only one instance can be realized in the system.

Writing Singleton Patterns with new Method

Writing Singleton Mode-Defected Edition with new Method

class MusicPlayer(object):
    # Record the first reference to the created object
    instance = None

    def __new__(cls, *args, **kwargs):
        # To determine whether a class attribute has a value, None indicates that it is the first object to be created.
        # If it is the first object, it assigns a reference to the class attribute and returns a reference to the object recorded by the class attribute.
        # If it is not the first object, the reference to the object recorded in the class attribute is returned if the reference to the object already exists in the class attribute.
        if cls.instance is None:
            cls.instance = super().__new__(cls)

        return cls.instance

    def __init__(self):
        print("Player initialization")


player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)

# Player initialization
# <__main__.MusicPlayer object at 0x000002C117E892E8>
# Player initialization
# <__main__.MusicPlayer object at 0x000002C117E892E8>

Writing Singleton Mode with new Method - Improved Version

Problem: A singleton cannot be initialized only once

There is a problem above. Although the reference of each return object is the same, the initialization method needs to be invoked every time the object is created, and we don't need it. So we need to modify the initialization method so that it can be initialized only once.

Each time an object is created with a class name (), the python interpreter automatically calls two methods:
_ new_ Allocation Space
_ init_ object initialization
After the modification of the _new_ method in the previous section, each time a unique reference is created for the first time
However: the initialization method will be called again

Requirement: Let the initialization method be executed only once

Solution:
1. Define a flag that identifies whether an initialization action has been performed, with an initial value of Flase
2. In the init method, judge flag and perform initialization if it is Flase.
3. Then set flag to True
4. In this way, when the init method is automatically called again, the initialization action will not be executed again.

Demonstration of improved version singleton model

class MusicPlayer(object):
    # Record the first reference to the created object
    instance = None
    # Record whether initialization has been performed
    flag = False

    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)

        return cls.instance

    def __init__(self):
        # Determine whether initialization has been performed
        # Once it has been executed, it returns directly and no more follow-up actions are executed.
        if MusicPlayer.flag:
            return
        # Not executed, indicating that the initialization is the first time, the initialization action is completed, and the class attribute identification is modified.
        print("Player initialization")
        MusicPlayer.flag = True


player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)

# Player initialization
# <__main__.MusicPlayer object at 0x000001ACFC4F9358>
# <__main__.MusicPlayer object at 0x000001ACFC4F9358>

Posted by xmitchx on Sat, 11 May 2019 12:59:11 -0700