python实现单例模式

动机

最近在写一个连接池,而连接池管理类不可避免的需要使用单例来保证所有用户在取得连接时取到的一定是同一个管理对象。故将此模式取来研究一番。

模式介绍

保证一个类仅有一个实例,并提供一个访问它的全局访问点 ——《设计模式》

思路

单例模式是全局只有一个访问点,故对于一个类来说,任何实例化后访问到的都应该是同样的对象。而也有另外一种变通思路,即访问的不是同一个对象,但其中数据是一样的。对于第一种思路,可以在类新建的时候检查是否之前已经被创建过。如果已经被创建过,则返回上次创建的对象,否则新建一个对象。也可以定义一个工厂来直接保存一个类的实例,客户端向工厂请求时则返回此实例。对于第二种思路,可以将类中的属性保存在类中,每次新建类的时候将同样的属性赋予类,这样,虽然每次返回的不是同一个对象,但其属性相同。

实现

如上所述,方法一、三基于第一种思路,方法二基于第二种思路。

方法一

在类的首次实例化时即保存一个全局的对象,之后再次实例化时即直接返回此对象

class Singleton(object):
    def __new__(cls):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton,cls).__new__(cls)
        return cls._instance    

s2=Singleton()
s3=Singleton()
s4=Singleton()
print id(s2),id(s3),id(s4)

结果为

>>> 
49981368 49981368 49981368

注:使用此方法需要Singleton类为新式类,即继承了object类才可以使用super来找到父类

方法二

在类中保留一个全局的字典,用来存储类中出现的属性。在new时将实例中的__dict__用此字典代替,使所有对象均使用此全局字典来保存属性。

class Singleton2(object):
    _att={}
    def __new__(cls):
        o = super(Singleton2, cls).__new__(cls)
        o.__dict__ = cls._att
        return o 

s2=Singleton2()
s3=Singleton2()
s2.a = 3
s3.c = 20
print id(s2),id(s3)
print s2.a,s2.c
print s3.a,s3.c

结果为

>>> 
48998440 48998496
3 20
3 20

注:此方法有局限。因为如果在类中使用了__slots__之后,则无法使用__dict__来管理属性。例如

class Singleton2(object):
    __slots__=['a','b']
    _att={}
    def __new__(cls):
        o = super(Singleton2, cls).__new__(cls)
        o.__dict__ = cls._att
        return o

s2=Singleton2()
s3=Singleton2()
s2.a = 3
s3.c = 20
print id(s2),id(s3)
print s2.a,s2.c
print s3.a,s3.c

结果报错

>>> 

Traceback (most recent call last):
  File "C:\Users\xxx\Desktop\so.py", line 38, in <module>
    s2=Singleton2()
  File "C:\Users\xxx\Desktop\so.py", line 17, in __new__
    o.__dict__ = cls._att
AttributeError: 'Singleton2' object has no attribute '__dict__'

另:slots无法继承。即带有slots的类的子类中不再有slots限制。如果想继承父类的slots,则需要在子类中也加入slots,此时限制的效果为父类与子类slots内容的并集。

方法三

另外借助工厂模式,定义一个工厂类或方法。在此工厂中保存一个已经创建好的类实例,

class t:
    pass
class Factory:
    ins = t()
    def createSingleton(self):
        return self.ins
if __name__ == '__main__':    
    s1=Factory()
    s2=Factory()
    os1=s1.createSingleton()
    os2=s2.createSingleton()

    print id(os1),id(os2)

结果为

>>> 
30703064 30703064
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值