[GO] Learn the design pattern "Singleton" with Python

As a material for learning GoF design patterns, the book "Introduction to Design Patterns Learned in the Augmented and Revised Java Language" seems to be helpful. However, since the examples taken up are based on JAVA, I tried the same practice in Python to deepen my understanding.

■ Singleton

The Singleton pattern (singleton pattern) is one of the design patterns in an object-oriented computer program. Defined by the GoF (Gang of Four; 4 gangs). The Singleton pattern is a design pattern that guarantees that only one instance of the class will be created. Used to implement mechanisms that must be absolutely unified across the application, such as locale and look and feel 600px-Singleton_UML_class_diagram.svg.png (The above is quoted from Wikipedia)

■ "Singleton" sample program

Let's define a class that can only create one instance.

Main.py


class Singleton(object):
    def __new__(cls, *args, **kargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

class Myclass(Singleton):
    def __init__(self, input):
        self.input = input

if __name__ == '__main__':
    one = Myclass(1)
    print("one.input={0}".format(one.input))
    two = Myclass(2)
    print("one.input={0}, two.input={1}".format(one.input, two.input))
    one.input = 0
    print("one.input={0}, two.input={1}".format(one.input, two.input))

Try to move

$ python Main.py 
one.input=1
one.input=2, two.input=2
one.input=0, two.input=0

I see, it behaves like a global variable.

□ Memorandum

(1) What is the difference between __new__ and __ init__?

1. In the case of __new__ (Hereafter, quoted from" Python language reference ")

-** Called to create a new instance of class cls. ** ** -** Take the class cls, which is requested to instantiate, as the first argument. ** ** --The remaining arguments are passed to the object's constructor expression (class call statement). -** The return value of __new__ () must be an instance of the new object (usually an instance of cls). ** ** --In a typical implementation, when creating a new instance of a class, specify the appropriate argument to super (). __ new__ (cls [, ...]) and use the super class's __new__ () method. Call it, make the necessary changes to the newly created instance, and then return it. -** If __new__ () does not return an instance of cls, the instance's__init __ ()method will not be called. ** ** --The main purpose of __new__ () is to customize instantiation with subclasses of immutable types (int, str, tuple, etc.). It is also often overridden in custom metaclasses to customize class generation.

Called before the instance object is created, the first argument cls is assigned a class object, and the purpose is to instantiate the object self. Shin.

2. In the case of __init__ (Hereafter, quoted from" Python language reference ")

--Called after the instance is created (by __new__ ()) and before it is returned to the caller. --The argument is what you passed to the class's constructor expression. --If both the base class and its derived class have __init __ () methods, the derived class's __init __ () method explicitly calls the base class's __init __ () method to make the base class part of the instance. Must be ensured that is properly initialized. For example, super () .__ init__ ([args ...]). --__new__ () and __init __ () work together to form an object (__new __ () creates and__init __ ()customizes it), so it's not from__ init __ () Do not return a None value; doing so will throw a TypeError at run time.

Called after the instance object is created, the instance object is assigned to the first argument self, and the purpose is to initialize the object self. ..

(2) Try to write the original "Singleton"

Try writing a Singleton without using the __new__ method.

Main.py


class Singleton(object):
    @classmethod
    def get_instance(cls, input):
        if not hasattr(cls, "_instance"):
            cls._instance = cls(input)
        else:
            cls._instance.input = input
        return cls._instance

class Myclass(Singleton):
    def __init__(self, input):
        self.input = input

if __name__ == '__main__':
    one = Myclass.get_instance(1)
    print("one.input={0}".format(one.input))
    two = Myclass.get_instance(2)
    print("one.input={0}, two.input={1}".format(one.input, two.input))
    one.input = 0
    print("one.input={0}, two.input={1}".format(one.input, two.input))

Try to move

$ python Main.py 
one.input=1
one.input=2, two.input=2
one.input=0, two.input=0

This style is simpler to use. I often see it in OpenStack or code reading.

■ Reference URL

-[Finishing "Introduction to Design Patterns Learned in Java Language" (Not)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java Introduction to Design Patterns Learned in Language-Finishing-Not-2cc9b34a30b2) -Singleton pattern from "diary of tachikawa844"

Recommended Posts