¥单例模式¥

单例模式

  • 学习单例模式就是为了,防止内存地址混乱

  • 实例化得到一个对象,内存地址相同

【一】什么是单例模式

  • 单例设计模式(Singleton Design Pattern):一个类只允许创建一个对象(或者实例),那么这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。

  • 当一个类的功能比较单一,只需要一个实例对象就可以完成需求时,就可以使用单例模式来节省内存资源。

【通常】单例模式创建的对象是进程唯一的, 单例类中对象的唯一性的作用范围是进程内的,在进程间是不唯一的。

【二】实现单例模式的方法

  • 使用模块

  • 使用装饰器

  • 使用类(方法)

  • 基于__new__方法实现

  • 基于元类metaclass实现

【三】类属性

(1)类产生对象

  • 创建一个普通的类

class MysqlControl(object):
    ...
​
#类只要加 () 实例化就会产生一个全新的对象
one = MysqlControl()
two = MysqlControl()
#查看对象  --- 发现虽然是同一个类实例化得到的对象,但是对象的地址不一样
print(one)#<__main__.MysqlControl object at 0x0000025C0F2FFFD0>
print(two)#<__main__.MysqlControl object at 0x0000025C0F2FECB0>
​
print(one is two)#False
  • 虽然是同一个类实例化得到的对象,但是对象的地址不一样

(2)类属性包装成方法

class Singleton(object):
    _instance = None
​
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
​
    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = Singleton('127.0.0.1', 3306)
        return cls._instance
​
​
obj_one = Singleton.get_instance()
obj_two = Singleton.get_instance()
​
print(obj_one)
#<__main__.Singleton object at 0x00000226E33B7E80>
print(obj_two)
# <__main__.Singleton object at 0x00000226E33B7E80>
print(obj_one is obj_two)
# True
# 输出 True,表示是同一个实例
  • 使用类属性保存属性,通过类方法获取实例

  • 在第一次调用get_instance方法时创建实例,并在后续调用中直接返回该实例。

(3)装饰器

def singleton(cls):
    instances = {}
​
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
            print(cls)#<class '__main__.Singleton'>
            #得到一个字典,{类:对象}
            print(instances)#{<class '__main__.Singleton'>: <__main__.Singleton object at 0x000002D50E217E20>}
            #字典的特性,键取值
            print(instances[cls])#得到对象#<__main__.Singleton object at 0x000002D50E217E20>
        #存在直接返回对象
        return instances[cls]
​
    return wrapper
​
​
@singleton
class Singleton:
    pass
​
​
singleton_one = Singleton()
singleton_two = Singleton()
print(singleton_one)
# <__main__.Singleton object at 0x000001C0B531A770>
print(singleton_two)
# <__main__.Singleton object at 0x000001C0B531A770>
print(singleton_one is singleton_two)
# True
# 输出 True,表示是同一个实例
​
# # 使用 __call__ 方法获取单例
singleton_three = Singleton()
print(singleton_one is singleton_three)
# True
  • 使用装饰器将原来的类包装成一个新的类,通过闭包和字典保存实例。

  • 在每次实例化时,先检查字典中是否已经存在该类的实例,如果不存在才创建实例并返回。

(4)元类(metaclass)

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        #instance相当于一个标志位
        #cls里面有没有这个instance属性,或者实例
        if not hasattr(cls, 'instance'):
            #得到一个对象
            cls.instance = super().__new__(cls)
            #就是为了生成一个对象
            print(super().__new__(cls))##<__main__.Singleton object at 0x000001C03DA97E50>
            print(cls)#<class '__main__.Singleton'>
            print(cls.instance)#<__main__.Singleton object at 0x000001C03DA97E50>
            print(hasattr(cls, 'instance'))#True
            print(cls.instance)#<__main__.Singleton object at 0x00000284256C7E50>
        return cls.instance
​
​
singleton_one = Singleton()
singleton_two = Singleton()
​
print(singleton_one)
#<__main__.Singleton object at 0x000002232A817E80>
print(singleton_two)
# <__main__.Singleton object at 0x000002232A817E80>
print(singleton_one is singleton_two)
# True
​
# 输出 True,表示是同一个实例
​
# 使用 __call__ 方法获取单例
singleton_three = Singleton()
print(singleton_one is singleton_three)
# True
  • 定义一个元类,在元类的__call__方法中判断实例是否已存在,如果不存在则调用父类的__call__方法来创建并返回实例。

(5)基于__new__方法

(1)思路
  • 在Python中,对象的实例化过程通常遵循以下步骤:

    • 首先,执行类的__new__方法,如果未定义此方法,将默认调用父类的__new__方法来创建一个实例化对象。

    • 接着,再执行__init__方法来对这个新创建的对象进行初始化。

  • 我们可以充分利用这个实例化过程来实现单例模式。

    • 具体做法是在类的__new__方法中判断是否已经存在实例,如果存在,则直接返回现有的实例,否则创建一个新的实例。

    • 这样就能够确保只有一个实例存在,从而实现了单例模式的效果。

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        #instance相当于一个标志位
        #cls里面有没有这个instance属性,或者实例
        if not hasattr(cls, 'instance'):
            #得到一个对象
            cls.instance = super().__new__(cls)
            #就是为了生成一个对象
            print(super().__new__(cls))##<__main__.Singleton object at 0x000001C03DA97E50>
            print(cls)#<class '__main__.Singleton'>
            print(cls.instance)#<__main__.Singleton object at 0x000001C03DA97E50>
            print(hasattr(cls, 'instance'))#True
            print(cls.instance)#<__main__.Singleton object at 0x00000284256C7E50>
        return cls.instance
​
​
singleton_one = Singleton()
singleton_two = Singleton()
​
print(singleton_one)
#<__main__.Singleton object at 0x000002232A817E80>
print(singleton_two)
# <__main__.Singleton object at 0x000002232A817E80>
print(singleton_one is singleton_two)
# True
​
# 输出 True,表示是同一个实例
​
# 使用 __call__ 方法获取单例
singleton_three = Singleton()
print(singleton_one is singleton_three)
# True
  • 重写__new__方法,在实例化对象时判断类中是否已有实例,如果没有则调用父类的__new__方法来创建并返回。

【6】基于模块

# singleton.py
class Singleton:
    pass
​
singleton_instance = Singleton()
  • 将实例化操作放在模块级别,通过导入该模块来获取实例。

  • 由于Python模块在运行时只会被导入一次,因此保证了实例的单一性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值