zoukankan      html  css  js  c++  java
  • 聊一聊python的单例模式

    单例模式

    单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

    四种方法:

    • 使用模块
    • 使用 __new__
    • 使用装饰器(decorator)
    • 使用元类(metaclass)
    • 使用类方法

    1. 使用__new__()

    import threading
    
    Lock = threading.Lock()
    
    # 加锁为了保证线程安全
    
    class Foo(object):
        __isinstance = None
    
        def __new__(cls, *args, **kwargs):
            # 如果发现__isinstance 有值了直接返回,不进锁了
            if not cls.__isinstance:
                with Lock:
                    if not cls.__isinstance:
                        cls.__isinstance =  super(Foo,cls).__new__(cls)
            return cls.__isinstance
    
    
    obj = Foo()
    obj2 = Foo()
    
    print(obj,obj2)

    2. 模块导入

    其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

    # mysingleton.py
    class My_Singleton(object):
        def foo(self):
            pass
     
    my_singleton = My_Singleton()
    

    将上面的代码保存在文件 mysingleton.py 中,然后这样使用:  

    from mysingleton import my_singleton
     
    my_singleton.foo()
    

      

    3. 使用装饰器

    基本思想为:

    1、在装饰器中添加一个字典类型的自由变量_instance;

    2、在闭包中判断类名是否存在于_instance中,如果不存在则创建一个类的事例,并讲其添加到字典中;如果存在则不进行实例化,直接返回字典中的实例;

    def Singleton(cls):  
        _instance = {}  
        def _singleton(*args, **kargs):  
            if cls not in _instance:  
                _instance[cls] = cls(*args, **kargs)  
            return _instance[cls]  
        return _singleton  
     
     
    @Singleton  
    class A(object):  
        a = 1  
        def __init__(self, x = 0):  
            self.x = x  
      
      
    a1 = A(2)  
    a2 = A(3)  
    print id(a1)  
    print id(a2)  
    print a1.x  
    print a2.x  
      
      
    ''''' 
    ---------------------------------------- 
    45838576 
    45838576 
    2 
    2 
    '''  

     

    4. 使用元类

    示例化一个类的时候,如果他有元类,先执行元类的__call__方法,cll方法的第一个参数就是子类,先执行子类的__new__,子类没有执行objects的__new__,实例化后执行初始化__init__ ,修改isinstance的值并返回

    import threading
    
    Lock = threading.Lock()
    
    
    class Singleton(type):
    
        def __call__(cls, *args, **kwargs):
            if not hasattr(cls,"isinstance"):
                with Lock:
                    if not hasattr(cls,"isinstance"):
                        obj = cls.__new__(cls,*args,**kwargs)
                        obj.__init__(*args,**kwargs)
                        setattr(cls,"isinstance",obj)
                    return getattr(cls,"isinstance")
            return getattr(cls,"isinstance")
    
    class Foo(object,metaclass=Singleton):
    
        def __init__(self):
            self.name = "zhou"
    
    
    obj = Foo()
    obj2 = Foo()
    
    print(obj,obj2)

     

    5. 使用类方法的单例模式

    加锁为类线程安全

    import threading
    import time
    
    class Foo(object):
        instance = None
        lock = threading.Lock()
    
        def __init__(self):
            self.a1 = 1
            self.a2 = 2
            import time
            import random
            time.sleep(2)
    
        @classmethod
        def get_instance(cls,*args,**kwargs):
            if not cls.instance:
                with cls.lock:
                    if not cls.instance:
                        obj = cls(*args,**kwargs)
                        cls.instance = obj
                    return cls.instance
            return cls.instance
    def task():
        obj = Foo.get_instance()
        print(obj)
    
    import threading
    for i in range(5):
        t = threading.Thread(target=task,)
        t.start()
    
    time.sleep(10)
    # 实例化时调用get_instance
    Foo.get_instance()

     

  • 相关阅读:
    大爆炸集成 Big Bang
    How:怎么做集成测试
    Where:对什么部分做集成测试
    web预览图片
    对象的属性赋值
    Web请求
    Sql Server 获取数据库最近执行的操作
    服务安装脚本
    生成并保存二维码图片,此方法最清晰
    c# get,set设置默认值
  • 原文地址:https://www.cnblogs.com/zhoujunhao/p/8471617.html
Copyright © 2011-2022 走看看