zoukankan      html  css  js  c++  java
  • 单利模式及python实现方式

     

    单例模式

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

    比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象

    python实现单例模式

    使用模块实现

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

     mysingleton.py

    class Singleton:
        def foo(self):
            print('foo')
    
    singleton=Singleton()

    其他文件

    from mysingleton import singleton
    
    singleton.foo()

    装饰器实现

    def singleton(cls):
        _instance = {}
        def wraper(*args, **kargs):
            if cls not in _instance:
                _instance[cls] = cls(*args, **kargs)
            return _instance[cls]
    
        return wraper
    
    @singleton
    class A(object):
        def __init__(self, x=0):
            self.x = x
    
    
    a1 = A(2)
    a2 = A(3)

    最终实例化出一个对象并且保存在_instance中,_instance的值也一定是

    基于__new__方法实现

    当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式

    class Singleton():
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls,'_instance'):
                cls._instance=object.__new__(cls)
            return cls._instance
    
    class A(Singleton):
        def __init__(self,x):
            self.x=x
    
    a=A('han')
    b=A('tao')
    print(a.x)
    print(b.x)

    为了保证线程安全需要在内部加入锁

    import threading
    
    class Singleton():
        lock=threading.Lock
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls,'_instance'):
                with cls.lock:
                    if not hasattr(cls, '_instance'):
                        cls._instance=object.__new__(cls)
            return cls._instance
    
    class A(Singleton):
        def __init__(self,x):
            self.x=x
    
    a=A('han')
    b=A('tao')
    print(a.x)
    print(b.x)

     两大注意:

    1. 除了模块单例外,其他几种模式的本质都是通过设置中间变量,来判断类是否已经被实例。中间变量的访问和更改存在线程安全的问题:在开启多线程模式的时候需要加锁处理。

    2. __new__方法无法避免触发__init__(),初始的成员变量会进行覆盖。其他方法不会。

  • 相关阅读:
    最短路+线段交 POJ 1556 好题
    判断线段和直线相交 POJ 3304
    nginx配置pathinfo模式,解决访问404
    使用ORM关联关系,如何自己关联自己
    PHPCMS
    linux安装redis服务,配置PHP扩展
    后台银行卡算法
    静态类和非静态类
    PHP的闭包和匿名函数
    php获取前一天时间段,每个月的第一天到最后一天
  • 原文地址:https://www.cnblogs.com/hantaozi430/p/8605275.html
Copyright © 2011-2022 走看看