Python单例模式的各种姿势

什么是单例模式?

简单来讲,单例模式是一种设计模式,在实例化过程中,确保类有且只有一个特定类型的对象,并提供全局访问点。一般应用于日志记录、数据库操作等情形,这些情形的特点是:程序运行过程中只能生成一个实例,以避免对同一资源产生相互冲突的请求。

概况来说,单例模式有如下特点:

  • 确保类只有一个对象被创建
  • 为对象提供一个访问点,使程序可以全局访问该对象
  • 控制共享资源的并行访问
Python单例模式的实现方法

想要实现单例模式,常见的方法是将构造方法私有化,并创建一个静态方法来完成对象的初始化。而在Python中,由于无法创建私有的构造方法,通常需要完成以下两步:

  1. 只允许类生成一个实例
  2. 如果有实例了,则会重复提供同一个实例

代码实现:

class Singleton(object):
    def __new__(cls):
        if not hasattr(cls, "instance")
            cls.instance = super(Singleton, cls).__new__(cls)
            return cls.instance
single = Singleton()
single1 = Singleton()
print("I am single ", single)
print("I am single1 ", single1)
# 结果为
# I am single <__main__.Singleton object at 0X102078ba8>
# I am single1 <__main__.Singleton object at 0X102078ba8>

通过重写__new__方法,控制python对象的创建。对象single和single1都是通过__new__方法创建的,执行过程中会先检查对象是否已存在,如果存在则优先分配已存在的实例对象。

懒实例化的单例模式

有些时候,当导入模块时,我们可能会无意中创建一个对象,而此时根本用不到这个对象。类似懒加载,懒实例化确保我们在真正需要使用对象时才进行创建。

举个栗子:

class Singleton(object):
    __instance = None
    def __init__(self):
        if not Singleton.__instance:
            print("initial now")
        else:
            print("instance exist", self.getInstance())

    @classmethod
    def getInstance(cls):
        if not cls.__instance:
            cls.__instance = Singleton()
        return cls.__instance
single = Singleton()
# 类初始化,但没有创建对象
print("object create now:", single.getInstance())
# 创建对象
single1 = Singleton()
# 对象已创建,使用同一对象

在首次实例化时,调用了__init__方法,但并没有创建实例。真正创建对象是在getInstance方法调用时,如此一来便可以在使用时进行真正的创建。

模块级别的单例模式

Python中,导入机制通过如下方式来工作:

  1. 检查一个python模块是否已经导入
  2. 如果已经导入,则返回该模块对象;如果没导入,则导入该模块并实例化
  3. 当模块首次被导入时会进行初始化,而再次导入时就不再初始化,而是返回同一个对象

由此可见,python可以通过导入模块的方式可以实现单例模式。

状态级别的单例模式(单态模式)

我们通常所说的单例模式,指的是一个类有且只有一个对象。但另一种说法指出,有些时候程序中需要关注的是对象的状态,而非同一性。这种模式也被称作单态模式。

举个栗子:

class Brog:
    __shared_state = {"1" : "2"}
    def __init__(self):
        self.x = 1
        slef.__dict__ = self.__shared_state

b = Brog()
b1 = Brog()
b.x = 4
print(b)
print(b1)
print(b.__dict__)
print(b1.__dict__)
# 执行结果显示,b和b1不是同一个对象,但当对象b改变自身属性时,b1的状态也被改变

首先通过将类变量__shared_state赋值给__dict__,而python使用__dict__存储一个类所有对象的状态。把类变量__shared_state赋值给所有已创建的实例,这样当创建两个实例b和b1时,将得到两个不同的对象。而对象的状态则是相同的,这样当改变其中一个对象的变量时,另一个对象的状态也将被改变。

除此之外,还可以通过修改__new__方法来实现这种单例模式,而__new__方法是用来创建对象实例的:

class Borg(object):
    __shared_state = {}
    def __new__(cls):
        obj = super(Brog, cls).__new__(cls, *args, **kwargs)
        obj.__dict__ = cls.__shared_state
        return obj
元类级别的单例模式

元类是一个类的类,反过来说,一个类是它元类的实例。通过操作元类,可以创建自己类型的类。

Python中,一切皆对象。对于一个整数a=5,查看a的类型type(a)返回<type'int'>,说明a是int类型,而type(int)返回<type'type'>,这意味着存在一个元类,因为int是type类型的类。

类的定义由其元类决定,当使用类A创建一个类时,Python通过A=type(name, bases,dict)来创建:

  • name:类的名称
  • base:基类
  • dict:属性变量

如果一个类有自定义的元类,例如Meta1,则Python会通过A=Meta1(name,bases,dict)来创建类。

举个元类的栗子:

class MyInt(type):
    def __call__(cls, *args, **kwargs):
        print("My int", args)
        print("Do some thing")
        return type.__call__(cls, *args, **kwargs)


class int(metaclass=MyInt):
    def __init__(self, x, y):
        self.x = x
        self.y = y

i = int(4, 5)
# 输出结果为
# My int (4, 5)
# Do some thing

对于已经存在的类,创建新对象时,调用__call__方法。当使用int(4, 5)实例化int类时,元类MyInt的__call__被调用了,这意味着,元类控制着实例化操作。

由此可以想到,通过在元类中控制类的创建和对象实例化,实现单例模式(注意:为了控制类的创建和初始化,元类将覆盖__new____init__方法。)

简单实现一个单例模式:

class MetaSingleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class Logger(metaclass=MetaSingleton):
    pass

logger = Logger()
logger1 = Logger()
print(logger, logger1)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值