Implementation of singleton pattern using __new__ in Python and parsing

  • 2021-07-01 07:48:34
  • OfStack

Singleton pattern is a classic design pattern. Briefly speaking, the singleton pattern of a class is that it can only be instantiated once, and the instance variables are fixed when instantiated for the first time.

The common singleton pattern in Python is None, which is a typical design. if xxx is None or if xxx is not None are usually used for comparison operation.

Python implements singleton pattern

The code is as follows:


class MyClass:
  _instance = None 
  _first_init = False 
  def __new__(cls, *args, **kwargs):
    if not cls._instance:
      cls._instance = super().__new__(cls)
    return cls._instance
  def __init__(self, var1, var2):
    cls = type(self)
    if not cls._first_init:
      self.var1 = var1
      self.var2 = var2
      cls._first_init = True

As shown above, I created a class of MyClass, defining two class variables, the first being _ instance, which holds the instances created by the class. The second is _first_init, which is a Boolean value that holds whether the class is instantiated for the first time.

In the __new__ method (constructor), determine whether the class variable _instance exists, and if it has been instantiated, return directly. If this is the first instantiation, the instance is bound to the _instance class variable, creating the instance using super () .__new__ (cls), that is, calling the parent class object.__new__ (MyClass) to create the instance.

In the __init__ method (initialization function), we get the MyClass class through cls=type (self) to determine whether it is instantiated for the first time. If it is the first instantiation, the instance variable is bound. Otherwise, nothing will be done.

Running effect

Let's create two instances to compare


>>> instance1 = MyClass(1, 2)
>>> instance2 = MyClass(7, 5)
>>> id(instance1) == id(instance2)
True

>>> instance2.var1
1

As you can see, the memory addresses of both instances are the same, and the variables have been fixed after the first instantiation, and will not change globally.

This is the implementation of singleton pattern.

ps: Let's look at the class method, __new__ method and __init__ method parsing in Python

Create a class in a programming language with the term constructor. However, in Python, __init__ is generally regarded as a construction method, but it is not completely equivalent. In the build class, there is a special method __new__, which is equivalent to a constructor.

__new__ is a class method, and we need the @ classmethod decorator in front of the function when we define a class method, whereas __new__ does not because it is specially handled. To understand the __new__ method, let's first look at what a class method is.

Class method


class MyClass:

  @classmethod
  def test(cls):
    print(cls.__name__)
    
MyClass.test()
# Output  MyClass

In the MyClass class, the test method is a class method, and its first parameter is cls, which is actually MyClass class. Print cls.__name__ to see the result. Class methods can be called directly by class name. Method name (). Typically, class methods are alternative constructors.

Application of class method


>>> from datetime import datetime
>>> datetime.fromtimestamp(324234)
datetime.datetime(1970, 1, 5, 2, 3, 54)

As shown above, fromtimestamp in the built-in datetime package is a class method, and datetime objects can be constructed in many ways.

__new__ method


def __new__(cls, a):
  return super().__new__(cls)

__new__ is a class method, so the first parameter is cls, and the remaining parameters are required in the constructor. Normally, __new__ does not need to be defined, but only in metaclass programming, which can control the generation process of classes.

__new__ must return 1 instance (instance), passed into the self parameter in the __init__ method, which is the instance variable. Here, the __new__ method of the parent class (object) is returned to create a new instance. Equivalent to


obj = object.__new__(MyClass)
obj = MyClass()

# obj is an example, and the above two ways are equivalent

Where MyClass is a class and obj is an instance (instance)

__init__ method

If __new__ is the constructor, then __init__ is the initialization function, which binds variables to the instance and updates the instance's __dict__ dictionary. The first parameter, self, is the return value of __new__ and is an instance of the class. The __new__ method executes before the __init__ method


def __init__(self, a):
  self.a = a

Combined use


class MyClass:
  def __new__(cls, a):
    return super().__new__(cls)

  def __init__(self, a):
    self.a = a
obj = MyClass(3)
print(obj.a)

Key points

1. __new__ is the constructor and __init__ is the initialization function.
2.__new__ does not need to be defined manually, but is used in metaclass programming to control the generation process of classes.
3. __new__ is executed first, and then executes the __init__ binding instance variable.
4.__new__ must have a return value, which is an instance of the class and is received by the __init__ function, commonly called the self variable

Summarize


Related articles: