首页 快讯正文

瑞安天气预报:Python的6种方式实现单例模式

admin 快讯 2020-04-23 25 0

单例模式是一个软件的设计模式,为了保证一个类,无论挪用多少次发生的实例工具,都是指向同一个内存地址,仅仅只有一个实例(只有一个工具)。

实现单例模式的手段有很多种,但总的原则是保证一个类只要实例化一个工具,下一次再实例的时刻就直接返回这个工具,不再做实例化的操作。以是这里面的要害一点就是,若何判断这个类是否实例化过一个工具

这里先容两类方式:

  • 一类是通过模块导入的方式;
  • 一类是通过邪术方式判断的方式;
# 基本原理:
- 第一类通过模块导入的方式,借用了模块导入时的底层原理实现。
- 当一个模块(py文件)被导入时,首先会执行这个模块的代码,然后将这个模块的名称空间加载到内存。
- 当这个模块第二次再被导入时,不会再执行该文件,而是直接在内存中找。
- 于是,若是第一次导入模块,执行文件源代码时实例化了一个类,那再次导入的时刻,就不会再实例化。

- 第二类主要是基于类和元类实现,在'工具'的邪术方式中判断是否已经实例化过一个工具
- 这类方式,凭据实现的手法差别,又分为差别的方式,如:
- 通过类的绑定方式;通过元类;通过类下的__new__;通过装饰器(函数装饰器,类装饰器)实现等。

下面划分先容这几种差别的实现方式,仅供参考实现思绪,不做详细需求。

通过模块导入

# cls_singleton.py
class Foo(object):
    pass

instance = Foo()

# test.py
import cls_singleton

obj1 = cls_singleton.instance
obj2 = cls_singleton.instance
print(obj1 is obj2)

# 原理:模块第二次导入从内存找的机制

通过类的绑定方式

class Student:
    _instance = None	# 纪录实例化工具

    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def get_singleton(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = cls(*args, **kwargs)
        return cls._instance

stu1 = Student.get_singleton('jack', 18)
stu2 = Student.get_singleton('jack', 18)
print(stu1 is stu2)
print(stu1.__dict__, stu2.__dict__)

# 原理:类的绑定方式是第二种实例化工具的方式,
# 第一次实例化的工具保留成类的数据属性 _instance,
# 第二次再实例化时,在get_singleton中判断已经有了实例工具,直接返回类的数据属性 _instance

通过邪术方式__new__

class Student:

    _instance = None

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs):
        # if cls._instance:
        #     return cls._instance	# 有实例则直接返回
        # else:
        #     cls._instance = super().__new__(cls)	# 没有实例则new一个并保留
        #     return cls._instance	# 这个返回是给是给init,再实例化一次,也没有关系

        if not cls._instance:	# 这是简化的写法,上面注释的写法更容易提现判断思绪
            cls._instance = super().__new__(cls)
        return cls._instance


stu1 = Student('jack', 18)
stu2 = Student('jack', 18)
print(stu1 is stu2)
print(stu1.__dict__, stu2.__dict__)

# 原理:和方式2类似,将判断的实现方式,从类的绑定方式中转移到类的__new__中
# 归根结底都是 判断类有没有实例,有则直接返回,无则实例化并保留到_instance中。

通过元类

class Mymeta(type):

    def __init__(cls, name, bases, dic):
        super().__init__(name, bases, dic)
        cls._instance = None		# 将纪录类的实例工具的数据属性放在元类中自动界说了

    def __call__(cls, *args, **kwargs):	# 此call会在类被挪用(即实例化时触发)
        if cls._instance:				# 判断类有没有实例化工具
            return cls._instance
        else:							# 没有实例化工具时,控制类造空工具并初始化
            obj = cls.__new__(cls, *args, **kwargs)
            obj.__init__(*args, **kwargs)
            cls._instance = obj			# 保留工具,下一次再实例化可以直接返回而不用再造工具
            return obj


class Student(metaclass=Mymeta):
    def __init__(self, name, age):
        self.name = name
        self.age = age


stu1 = Student('jack', 18)
stu2 = Student('jack', 18)
print(stu1 is stu2)
print(stu1.__dict__, stu2.__dict__)

# 原理:类界说时会挪用元类下的__init__,类挪用(实例化工具)时会触发元类下的__call__方式
# 类界说时,给类新增一个空的数据属性,
# 第一次实例化时,实例化之后就将这个工具赋值给类的数据属性;第二次再实例化时,直接返回类的这个数据属性
# 和方式3的差别之处1:类的这个数据属性是放在元类中自动界说的,而不是在类中显示的界说的。
# 和方式3的差别之处2:类挪用时触发元类__call__方式判断是否有实例化工具,而不是在类的绑定方式中判断

函数装饰器

def singleton(cls):
    _instance_dict = {}		# 接纳字典,可以装饰多个类,控制多个类实现单例模式
  
    def inner(*args, **kwargs):
        if cls not in _instance_dict:
            _instance_dict[cls] = cls(*args, **kwargs)
        return _instance_dict.get(cls)
    return inner


@singleton
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # def __new__(cls, *args, **kwargs):	# 将方式3的这部门代码搬到了函数装饰器中
    #     if not cls._instance:
    #         cls._instance = super().__new__(cls)
    #     return cls._instan
    
stu1 = Student('jack', 18)
stu2 = Student('jack', 18)
print(stu1 is stu2)
print(stu1.__dict__, stu2.__dict__)

类装饰器

class SingleTon:
    _instance_dict = {}

    def __init__(self, cls_name):
        self.cls_name = cls_name

    def __call__(self, *args, **kwargs):
        if self.cls_name not in SingleTon._instance_dict:
            SingleTon._instance_dict[self.cls_name] = self.cls_name(*args, **kwargs)
        return SingleTon._instance_dict.get(self.cls_name)


@SingleTon		# 这个语法糖相当于Student = SingleTon(Student),即Student是SingleTon的实例工具
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

stu1 = Student('jack', 18)
stu2 = Student('jack', 18)
print(stu1 is stu2)
print(stu1.__dict__, stu2.__dict__)

# 原理:在函数装饰器的思绪上,将装饰器封装成类。
# 程序执行到与语法糖时,会实例化一个Student工具,这个工具是SingleTon的工具。
# 后面使用的Student本质上使用的是SingleTon的工具。
# 以是使用Student('jack', 18)来实例化工具,其实是在挪用SingleTon的工具,会触发其__call__的执行
# 以是就在__call__中,判断Student类有没有实例工具了。
,

sunbet

www.0577meeting.com提供官方APP下载,游戏火爆,口碑极好,服务一流,一直是sunbet会员的首选。

版权声明

本文仅代表作者观点,
不代表本站诚信在线的立场。
本文系作者授权发表,未经许可,不得转载。