【一】单例模式介绍
【1】什么是单例模式
- 一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式
【2】为什么要学单例模式
- 当一个类的功能比较单一,只需要一个实例对象就可以完成需求时,就可以使用单例模式来节省内存资源
【3】如何实现一个单例
- 在python中,我们可以使用多种方法来实现单例模式
- 使用模块
- 使用装饰器
- 使用类(方法)
- 基于
__new__
方法实现 - 基于元类metaclass实现
【二】类属性
- 使用类属性保存实例,通过类方法获取实例。
- 在第一次调用
get_instance
方法时创建实例,并在后续调用中直接返回该实例 - 类产生对象
# 创建一个普通的类
class Student(object):
pass
# 实例化类得到对象,类只要加()实例化就会产生一个全新的对象
stu1 = Student()
stu2 = Student()
print(id(stu1)) # 1711911837680
print(id(stu2)) # 1711911837680
# 两个对象的id不同
- 类属性包装成方法
class Student(object):
_instance = None
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = Student('ligo', 18)
return cls._instance
stu1 = Student.get_instance()
stu2 = Student.get_instance()
print(id(stu1)) # 2387386923232
print(id(stu2)) # 2387386923232
# id 相同,是同一个实例
【三】装饰器
- 使用装饰器将原来的类包装成一个新的类,通过闭包和字典保存实例。
- 在每次实例化时,先检查字典中是否已经存在该类的实例,如果不存在才创建实例并返回
def outer(cls):
instance = {}
def inner(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return inner
@outer
class MyClass(object):
pass
obj1 = MyClass()
obj2 = MyClass()
print(id(obj1)) # 2051247611504
print(id(obj2)) # 2051247611504
【四】元类
- 定义一个元类,在元类的
__call__
方法中判断实例是否已存在,如果不存在则调用父类的__call__
方法来创建并返回实例
class MyType(type):
def __init__(cls, class_name, class_bases, class_dict):
super(MyType, cls).__init__(class_name, class_bases, class_dict)
cls.instance = None
def __call__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = super(MyType, cls).__call__(*args, **kwargs)
return cls.instance
class MyClass(metaclass=MyType):
pass
obj1 = MyClass()
obj2 = MyClass()
print(id(obj1)) # 2202077462144
print(id(obj2)) # 2202077462144
# id 相同,是同一个实例
【五】基于__new__
方法
- 在Python中,对象的实例化过程通常遵循以下步骤:
- 首先执行类的
__new__
方法,如果未定义此方法,将默认调用父类的__new__
方法来创建一个实例化对象,然后再执行__init__
方法来对这个新创建的对象进行初始化
- 首先执行类的
- 利用实例化过程来实现单例模式:
- 在类的
__new__
方法中判断是否已经存在实例,如果存在,则直接返回现有实例,否则创建一个新实例 - 这样就能够确保只有一个实例存在,从而实现了单例模式的效果
- 在类的
class Student(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super().__new__(cls)
return cls._instance
stu1 = Student()
stu2 = Student()
print(id(stu1)) # 1711911837680
print(id(stu2)) # 1711911837680
# id相同,是同一个实例
# 重写__new__方法,在实例化对象时判断类中是否已有实例,如果没有则调用父类的__new__方法来创建并返回
【六】基于模块
class Student:
pass
instance = Student()
# 将实例化操作放在模块级别,通过导入该模块来获取实例。
# 由于Python模块在运行时只会被导入一次,因此保证了实例的单一性
标签:__,进阶,Python,instance,实例,单例,id,cls
From: https://www.cnblogs.com/ligo6/p/18183507