• Python 中,单例模式的5种实现方式(使用模块、使用装饰器、使用类方法、基于new方法实现、基于metaclass方式实现)


    单例模式的5种实现方式
    1 使用模块
    2 使用装饰器
    3 使用类方法
    4.基于new方法实现
    5 基于metaclass方式实现

    单例模式的5种实现方式

    什么是单例模式?
    单例模式是指:保证一个类仅有一个实例,并提供一个访问它的全局访问点
    
    # 线程1 执行:
    cursor.excute('select * from user')
    
    # 线程2执行 
    cursor.excute('select * from books')
    
    # 线程1 执行
    cursor.fetchAll() # 拿出查询到的数据
    
    # django ,每个线程,一个连接对象---》 连接池
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1 使用模块

    其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当
    第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
    因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
    如果我们真的想要一个单例类,可以考虑这样做:
    
    1.新建一个mysingleton.py
     class Singleton(object):
          def foo(self):
              pass
      singleton = Singleton()
    
    2.将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,
    这个对象即是单例模式的对象:
    from a import singleton
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2 使用装饰器

       def Singleton(cls):
            instance = None
            def _singleton(*args, **kargs):
                nonlocal instance
                if not instance:
                    instance = cls(*args, **kargs)
                return instance
            return _singleton
        
        @Singleton
        class A(object):
            def __init__(self, x=0):
                self.x = x
    
        a1 = A(2)
        a2 = A(3)
        print(a1.x)
        print(a2.x)
        
        print(a1 is a2)  # True
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    回顾装饰器是什么

    
    import time
    
    # 装饰器是什么?装饰器的作用是什么?
    '''
    装饰器是闭包函数的一个典型应用
    
    它是什么?
        在不改变函数源代码和调用方式idea基础上,为函数增加新功能
    '''
    
    
    # def add(a, b):
    #     time.sleep(2)
    #     return a + b
    
    
    def time_total(func):
        def inner(a, b):
            start = time.time()
            res = func(a, b)
            print('运行时间是:', time.time() - start)
            return res
    
        return inner
    
    
    # add = time_total(add)
    # res = add(3, 4)
    # print(res)
    
    
    @time_total  # 原理就是 add=time_total(add)
    def add(a, b):
        time.sleep(2)
        return a + b
    
    
    res = add(3, 4)
    print(res)
    print(add.__name__)  # 就是inner
    
    # 什么是闭包函数?参数不是传进来的,是用了它上一层作用域范围的变量
    '''
        1 定义在函数内部
        2 对外部作用域有引用(如果使用外部的可变类型,则直接使用;
            如果是不可变类型,需要使用nonlocal)
        
        例如:
        def add():
            a = 10
            def inner():
                nonlocal a
                a += 1
                print('闭包内部的值是:', a)  # 11
            inner()
            print('闭包外部的值是:', a)  # 11
        
        add()
    '''
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    3 使用类方法

    class Singleton(object):
        _instance=None
        def __init__(self):
            pass
        @classmethod
        def instance(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance=cls(*args, **kwargs)
            return cls._instance
    
    a1=Singleton.instance()
    a2=Singleton().instance()
    
    print(a1 is a2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4 基于new方法实现

    class Singleton(object):
        _instance=None
        def __init__(self):
            pass
    
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = object.__new__(cls)
            return cls._instance
    
    obj1 = Singleton()
    obj2 = Singleton()
    print(obj1 is obj2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5 基于metaclass方式实现

    
    # 产生类这个对象的类,称之为元类
    # 类中的 __call__什么时候回触发?对象()会触发
    class SingletonType(type):
        _instance = None
    
        def __call__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = object.__new__(cls)
                cls._instance.__init__(*args, **kwargs)
            return cls._instance
    
    
    class Foo(metaclass=SingletonType):
        def __init__(self, name):
            self.name = name
    
    
    obj1 = Foo('name')
    obj2 = Foo('name')
    print(obj1.name)
    print(obj1 is obj2)  # True
    
    # __init__ 和 __new__ 区别是什么?
    # 1 类()--->触发类中的__init__---->对象已经创建出来了,不能拦截住,做成单例了
    # 2 类()----》触发类中的__new__----》真正的创建对象,判断之前有没有创建过,如果创建过,直接返回
    # 3元类---》类()--->触发元类的__call__---》判断之前有没有创建过,如果有,直接返回
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    如何应对访问国外服务器缓慢的问题?SDWAN组网是性价比之选
    单片机-控制按键点亮LED灯
    第08章 长期依赖与优化策略
    Minikube 基础操作2:应用操作
    QT多线程项目中子线程无法修改主线程的ui组件
    C/C++输入输出流函数大全
    PTA 7-6 数据类型判断(c++)
    Cheat Engine 学习
    如何绘制Top级美图?20+案例分享
    直播带货小程序的前端开发技巧与工具
  • 原文地址:https://blog.csdn.net/weixin_44145338/article/details/133876996