python实现单粒模式,模块方法/装饰器方法/__new__方法

时间:2022-05-22 22:26:52

我们首先理解一下什么叫做单例模式。

就是说,系统环境里面有一个类,无论在系统的什么地方,只要想实例化,就只能得到一个实例,实例化后对实例的任何操作,也只和第一个实例相关。

另外一个层面,单例模式同样避免了重复实例化的内存浪费,如果使用得当,能够大大节约系统资源。

 

下面就说一下python里面实现实例的几种方法,里面有几个和我之前讲过的知识点相关,这里mark一下:

  • 使用模块
  • 使用魔法方法 __new__
  • 使用装饰器

1.模块方法实施单例模式,这个方法很简单,很土,但是很好理解:

singleton.py

import datetime
class ModuleSingleton(object):
    def __init__(self):
        self.init_time = str(datetime.datetime.now())
    def gatherAttrs(self):
        return ",".join("{}={}".format(k, getattr(self, k))
                        for k in self.__dict__.keys())
    def __str__(self):
        return "[{}:{}]".format(self.__class__.__name__, self.gatherAttrs())
    __repr__ = __str__

myinstance = ModuleSingleton()

下面我们来测试一下:

test.py

from singleton import test_module_singleton
def get_first_instance():

    return test_module_singleton.myinstance

def get_second_instance():

    return test_module_singleton.myinstance

def main():
    obj1 = get_first_instance()
    obj2 = get_second_instance()
    print obj1, obj2
    print id(obj1), id(obj2)

if __name__ == '__main__':

   main()

下面是输出,发现他们的初始化时间,以及实例的id,完全一模一样。

pydev debugger: starting (pid: 16531) [ModuleSingleton:init_time=2018-03-11 15:21:39.690618] [ModuleSingleton:init_time=2018-03-11 15:21:39.690618] 140711470863632 140711470863632


2.使用__new__方法实现单粒,这里的__dict__,super,__init__请自行脑补一下:

import datetime
class MagicNewSingleton(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(MagicNewSingleton, cls).__new__(cls, *args, **kw)  
        return cls._instance
    def __init__(self):
        self.init_time = str(datetime.datetime.now())
    def gatherAttrs(self):
        return ",".join("{}={}".format(k, getattr(self, k))
                        for k in self.__dict__.keys())
    def __str__(self):
        return "[{}:{}]".format(self.__class__.__name__, self.gatherAttrs())

    __repr__ = __str__


if __name__ == '__main__':
    obj1 = MagicNewSingleton()
    obj2 = MagicNewSingleton()
    print obj1, obj2

    print id(obj1), id(obj2)

我们看一下输出结果,和第一种实现方式一样的效果:

[MagicNewSingleton:init_time=2018-03-11 15:40:33.918990] [MagicNewSingleton:init_time=2018-03-11 15:40:33.918990] 139931646473232 139931646473232


3.使用装饰器实现单粒模式,这里有关装饰器,闭包的内容,请自行脑补一下吧:

import datetime
from functools import wraps
def decorator_singleton(cls):
    instances = {}
    @wraps(cls)
    def getinstance(*args, **kw):
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return getinstance
@decorator_singleton
class DecoratorSingleton(object):
    def __init__(self)
        self.init_time = str(datetime.datetime.now())
    def gatherAttrs(self):
        return ",".join("{}={}".format(k, getattr(self, k))
                        for k in self.__dict__.keys())
    def __str__(self):
        return "[{}:{}]".format(self.__class__.__name__, self.gatherAttrs())
    __repr__ = __str__

if __name__ == '__main__':
    obj1 = DecoratorSingleton()
    obj2 = DecoratorSingleton()
    print obj1, obj2

    print id(obj1), id(obj2)

最后看一下输出:

[DecoratorSingleton:init_time=2018-03-11 15:51:50.268966][DecoratorSingleton:init_time=2018-03-11 15:51:50.268966]

140602111509648 140602111509648

总结一下:

  • 模块方法,只需要在一个模块里面完成实例化,在其他模块使用时直接导入即可。(详细的,请先理解模块的概念,包括locals(), globals()两个方法)。
  • __new__方法,重新实现类的'构造函数',使用类变量辨识类是否完成了初始化。
  • 装饰器方法,使用闭包变量来辨识类是否完成了初始化。