• python实现单例的五种方式


    单例模式

    ​ 单例模式是一个软件的设计模式,为了保证一个类,无论调用多少次产生的实例对象,
    ​ 都是指向同一个内存地址,仅仅只有一个实例(对象)!

    五种单例:

    - 模块
    - 装饰器
    - 元类
    - __new__
    - 类方法: classmethod
    

    方式一: @classmethod ---> 通过类方法来实现单例

    class Foo(object):
        # 定义了一个类的数据属性,
        # 用于接收对象的实例,判断对象的实例是否只有一个
        _instance = None  # obj1
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        @classmethod
        def singleton(cls, *args, **kwargs):
            # 判断类属性_instance是否有值,有代表已经有实例对象
            # 没有则代表没有实例对象,则调用object的__init__获取实例对象
            if not cls._instance:
                # object.__new__(cls): 创造对象
                # 没有参数情况下
                # cls._instance = object.__new__(cls, *args, **kwargs)
    
                # 有参数的情况下
                cls._instance = cls(*args, **kwargs)  # Foo()
    
            # 将已经产生的实例对象  直接返回
            return cls._instance
    
    
    obj1 = Foo.singleton('tank', '123')
    obj2 = Foo.singleton('tank', '123')
    # print(obj1 is obj2)
    

    方式二: 元类

    class MyMeta(type):
    
        # 1、先触发元类里面的__init__
        def __init__(self, name, base, attrs):  # self --> Goo
            # *** 造空的对象, 然后赋值给了Goo类中的_instance类属性
            self._instance = object.__new__(self)
            # 将类名、基类、类的名称空间,传给type里面的__init__
            super().__init__(name, base, attrs)
            # type.__init__(self, name, base, attrs)
    
        # 2、当调用Goo类时,等同于调用了由元类实例化的到的对象
        def __call__(self, *args, **kwargs):
            # 判断调用Goo时是否传参
            if args or kwargs:
                init_args = args
                init_kwargs = kwargs
    
                # 1)通过判断限制了用于传入的参数必须一致,然后返回同一个对象实例
                if init_args == args and init_kwargs == kwargs:
                    return self._instance
    
                # 2) 若不是同一个实例,则新建一个对象,产生新的内存地址
                obj = object.__new__(self)
                self.__init__(obj, *args, **kwargs)
                return obj
    
            return self._instance
    
    
    class Goo(metaclass=MyMeta):  # Goo = MyMeta(Goo)
        # _instance = obj
        def __init__(self, x):
            self.x = x
    
    g1 = Goo('1')
    g2 = Goo('1')
    # print(g1 is g2)  # True
    

    方式三: __new__实现

    通过调用类方法实例化对象时,自动触发的__new__来实现单例

    class Aoo(object):
        _instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = object.__new__(cls)
    
            return cls._instance
    
    a1 = Aoo()
    a2 = Aoo()
    # print(a1 is a2)  # True
    

    方式四: 装饰器实现

    通过调用类方法实例化对象时,自动触发的__new__来实现单例

    # 单例装饰器
    def singleton_wrapper(cls):  # cls ---> Too
        # 因为装饰器可以给多个类使用,所以这里采用字典
        # 以类作为key, 实例对象作为value值
        _instance = {
            # 伪代码: 'Too': Too的示例对象
        }
    
        def inner(*args, **kwargs):
            # 若当前装饰的类不在字典中,则实例化新类
            # 判断当前装饰的Too类是否在字典中
            if cls not in _instance:
                # obj = cls(*args, **kwargs)
                # return obj
                # 不在,则给字典添加 key为Too, value为Too()---> 实例对象
                # {Too: Too(*args, **kwargs)}
                _instance[cls] = cls(*args, **kwargs)
    
            # return 对应的实例对象cls(*args, **kwargs)
            return _instance[cls]
    
        return inner
    
    @singleton_wrapper  # singleton_wrapper(Too)
    class Too(object):
        pass
    
    t1 = Too()
    t2 = Too()
    # print(t1 is t2)  # True
    
    

    方式五: 模块导入实现

    重复导入模块不会重新生成对应的名称空间和作用域

    import cls_singleton
    
    s1 = cls_singleton.instance
    s2 = cls_singleton.instance
    
    print(s1 is s2)  # True
    
  • 相关阅读:
    一本通 1297:公共子序列
    【未完】一本通 1277:【例9.21】方格取数
    一本通 1295:装箱问题
    一本通 1268:【例9.12】完全背包问题
    【BZOJ4416】阶乘字符串(SHOI2013)-状压DP
    【BZOJ2658】小蓝的好友(ZJOI2012)-扫描线+Treap
    【BZOJ2159】Crash的文明世界-第二类斯特林数+树形DP
    【HDU4336】Card Collector-Min-Max容斥
    【BZOJ3997】组合数学(TJOI2015)-Dilworth定理+DP
    【LOJ2537】Minimax(PKUWC2018)-树形DP+线段树合并
  • 原文地址:https://www.cnblogs.com/Henry121/p/13552996.html
Copyright © 2020-2023  润新知