Click to jump to the Python Notes home directory

This program recording

A, content,

Second, the role of

Three, use scenarios

Four advantages,

Five, the singleton pattern of four ways to achieve

  • 1. Form of file import (common)
  • 2. Singleton pattern based on class implementation
  • 3. Singleton pattern based on __new__ implementation (most commonly used
  • 4. Singleton pattern based on metaclass

Application of singleton pattern (will be used in the database connection pool singleton pattern)

Seven, an additional supplement to the simple profit model with decorators


A, content,

Ensure that a class has only one instance and provide a global access point to access it

Second, the role of

Singletons, that is, only one instance of a class

Three, use scenarios

When a class has only one instance and customers can access it from a well-known point of access such as database links and Socket creation links

Four advantages,

  • Controlled access to a unique instance
  • Controlled access to a unique instance

Simple interest is equivalent to global variables, but prevents the namespace from being polluted.

Try to ask? Why use singletons instead of global variables?

A. Global variables may have namespace interference and may be overwritten if they have the same name

Five, the singleton pattern of four ways to achieve

1. Form of file import (common)

s1.py

class Foo(object):
    def test(self):
        print("123")

v = Foo()
#v is an instance of Foo

s2.py
from s1 import v as v1
print(v1,id(v1))  #<s1.Foo object at 0x0000000002221710> 35788560

from s1 import v as v2
print(v1,id(v2))   #<s1.Foo object at 0x0000000002221710> 35788560

The memory address for both is the same
When a file is loaded, it will not be reloaded after the first import.
Copy the code

2. Singleton pattern based on class implementation

# # * * * * * * * * * * * * * * * * * * * * * * the singleton pattern: cannot support multithreading is * * * * * * * * * * * * * * =

class Singleton(object):

    def __init__(self):
        import time
        time.sleep(1)

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance

import threading

def task(arg):
    obj = Singleton.instance()
    print(obj)

for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()


# # * * * * * * * * * * * * * * * * * * * * the singleton pattern: support multithreading is * * * * * * * * * * * * * * * *,

import time
import threading
class Singleton(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        time.sleep(1)

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:   # lock internal for thread safety
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance


def task(arg):
    obj = Singleton.instance()
    print(obj)
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)


Obj = singleton.instance ()
# # example:
## obj1 = Singleton.instance()
## obj2 = Singleton.instance()
## print(obj1,obj2)
## Error example
## obj1 = Singleton()
## obj2 = Singleton()
## print(obj1,obj2)
Copy the code

3. Singleton based on __new__ implementation (most commonly used)

class Singleton:
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance

one = Singleton()
two = Singleton()

two.a = 3
print(one.a)
# # 3
## one is identical to two, and can be detected by id(), **, is
print(id(one))
# # 29097904
print(id(two))
# # 29097904
print(one ** two)
## True
print(one is two)

Copy the code

4. Singleton pattern based on metaclass

"""1. An object is a class creation. When an object is created, its __init__ method is automatically executed, and object () executes its __call__ method 2. Class () executes the __call__ method of type (class __new__ method, class __init__ method). Class Foo: def __init__(self): pass def call__(self, *args, **kwargs): pass ## The __call__ method of type ## 1.1 calls the __new__ method of class Foo (which is an object of type), which is used to create the object. ## 1.2 calls the __init__ method of class Foo (which is an object of type) to initialize the object. Step 2: Execute Foo's __call__ method obj()"""

## **********= execution flow of the class ****************
class SingletonType(type):
    def __init__(self,*args,**kwargs):
        print(self)  # Will it print? #
      
        super(SingletonType,self).__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs):  #cls = Foo
        obj = cls.__new__(cls, *args, **kwargs)
        obj.__init__(*args, **kwargs)
        return obj


class Foo(metaclass=SingletonType):
    def __init__(self,name):
        self.name = name
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls, *args, **kwargs)
' 'The __init__ () method is automatically executed when the class is created. The __call__ () method is automatically executed when the class is created. Class () first executes the __call__ method of type (calling the __new__, __init__ methods of the class). Foo is created by the SingletonType class.' '
obj = Foo("hiayan")


## ************ The third way to implement the singleton pattern ****************=
import threading

class SingletonType(type):
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

class Foo(metaclass=SingletonType):
    def __init__(self,name):
        self.name = name


obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)
Copy the code

Application of singleton pattern (will be used in the database connection pool singleton pattern)

pool.py

import pymysql
import threading
from DBUtils.PooledDB import PooledDB

class SingletonDBPool(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        self.pool = PooledDB(
            creator=pymysql,  ## Use the link database module
            maxconnections=6,  ## The maximum number of connections allowed by the pool. 0 and None indicate that the number of connections is not limited
            mincached=2,  At least one free link was created in the link pool during initialization. 0 means no link was created

            maxcached=5,  ## The maximum number of idle links in the link pool, 0 and None are not limited
            maxshared=3,
            ## The maximum number of links shared in the link pool. 0 and None indicate all links. PS: useless because modules such as Pymysql and MySQLdb have threadsafety of 1 and _maxcached is always 0 no matter what the value is set to, so all links are always shared.
            blocking=True,  If there is no connection available in the connection pool, whether to block waiting. True c. False, do not wait and then report an error
            maxusage=None,  ## The maximum number of times a link can be reused. None means unlimited
            setsession=[],  ## List of commands to execute before starting a session. ["set datestyle to...", "set time zone..."]
            ping=0,
            Ping MySQL server to check whether the service is available. # #, such as: 0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123',
            database='pooldb',
            charset='utf8'
        )

    def __new__(cls, *args, **kwargs):
        if not hasattr(SingletonDBPool, "_instance"):
            with SingletonDBPool._instance_lock:
                if not hasattr(SingletonDBPool, "_instance"):
                    SingletonDBPool._instance = object.__new__(cls, *args, **kwargs)
        return SingletonDBPool._instance

    def connect(self):
        return self.pool.connection()
Copy the code

app.py

from pool import SingletonDBPool

def run():
    pool = SingletonDBPool()
    conn = pool.connect()
    ## xxxxxx
    cursor = conn.cursor()
    cursor.execute("select * from td where id=%s", [5, ])
    result = cursor.fetchall()  ## Get data
    cursor.close()
    conn.close()

if __name__ ** '__main__':
    run()
Copy the code

An additional singleton pattern implemented with decorators

#
def wrapper(cls):
    instance = {}
    def inner(*args,**kwargs):
        if cls not in  instance:
            instance[cls] = cls(*args,**kwargs)
        return instance[cls]
    return inner

@wrapper
class Singleton(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

obj1 = Singleton('haiyan',22)
obj2 = Singleton('xx', 22)print(obj1)
print(obj2)
Copy the code