单例模式

ps:类只要加括号就会生成一个新的对象,无论参数是否相同,单例模式排除在外.

class Demo:
    pass

obj1 = Demo()
obj2 = Demo()
print(id(obj1))  # 1594519955888
print(id(obj2))  # 1594519955832

 单例:

多次调用类拿到的是同一个对象

单例的实现:

<1>基于classmethod

class Mysql(object):
    _instance = None
    def __init__(self, host, port):
        self.host = host
        self.port = port
    @classmethod
    def singelton(cls):
        if not cls._instance:
            cls._instance = cls('127.0.0.1',8080)
obj1 = Mysql.singelton()
obj2 = Mysql.singelton()
obj3 = Mysql('168.192.1.1',8088)
print(id(obj1), id(obj2), id(obj3))  # 1731962064 1731962064 1736639656680

<2>基于装饰器

# 基于装饰器  本质:会将紧挨着它的变量名当做参数传入
def singelton(cls):
    _instance = cls('127.0.0.1',8080)
    def inner(*args, **kwargs):
        if args or kwargs:
            obj = cls(*args, **kwargs)  # cls 是真正的 Mysql 类
            return obj
        return _instance
    return inner

@singelton   # Mysql = singelton(Mysql)  函数加括号优先级最高,此时 Mysql就是inner
class Mysql(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port

obj1 = Mysql()  # 其实是 inner()
obj2 = Mysql()
obj3 = Mysql('168.192.1.1',8088)
print(id(obj1), id(obj2), id(obj3))  # 2661019235384 2661019235384 2661019235328

<3>基于元类

class MyClass(type):
    def __call__(self, *args, **kwargs):
        # 调用 Mysql 中的 _instance
        if not getattr(self,'_instance'):  # 此时的self是Mysql
            self._instance = super().__call__(*args, **kwargs)  # 调用父类的__call__产生对象赋值给 _instance 这个对象就是Mysql的对象
            # __call__固定会做三件事:
            # 1.产生空对象  __new__
            # 2.初始化对象  __init__
            # 3.返回该对象  return obj
        return self._instance
    pass

class Mysql(object, metaclass=MyClass):  # 类加括号会走它元类中的__call__方法
    _instance = None
    def __init__(self, host, port):
        self.host = host
        self.port = port

obj1 = Mysql('168.192.1.1',8088)
obj2 = Mysql('168.192.1.1',9999)
print(id(obj1), id(obj2))  # 2107832088112 2107832088112

<4>基于__new__

class Mysql(object):
    _instance = None
    def __init__(self, host, port):
        self.host = host
        self.port = port
    # __new__拦截类的创建过程,在类创建前先走__new__, 这里的__new__在Mysql实例化时触发
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)  # 这里的cls每次都是最后实例化时那个Mysql
        return cls._instance

obj1 = Mysql('168.192.1.1',8088)
obj2 = Mysql('168.192.1.1',9999)
print(id(obj1), id(obj2))  # 1512390747976  1512390747976

<5>基于模块

class Settings(object):pass

settings = Settings()
单例设计模式1.py
from 单例设计模式1 import settings

def func():
    print(id(settings))
单例设计模式2.py
# 1.
from 单例设计模式1 import settings
print(id(settings))  # 3078907535488
from 单例设计模式1 import settings
print(id(settings))  # 3078907535488
# 模块导入一次后就不会在导入

# 2.
from 单例设计模式1 import settings
from 单例设计模式2 import func

print(id(settings))  # 2381785037456
func()  # 2381785037456

# 3.
from 单例设计模式1 import settings,Settings
print(id(settings))  # 2080793135592
print(id(Settings()))  # 2080793135424

 

posted @ 2019-10-31 08:19  waller  阅读(188)  评论(0编辑  收藏  举报