python的单例模式

单例模式

1、什么是单例模式

单例模式指的是类实例化时,只产生单个实例化对象。

实例化多个对象会产生不同的内存地址,单例可以让所有调用者,在调用类产生对象的情况下都指向同一份内存地址。

例如:打开文件。

单例的目的:为了减少内存的占用。

2、产生单例模式的四种方法

2.1 方法一:__new__

借助类内部的__instance属性,将object.__new__()产生的对象赋值给它。

如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回。

如果cls._instance不为None,直接返回cls._instance

这样就可以在实例化类时,保证使用的都是同一个对象。

class Singleton:

    __instance = None

    def __new__(cls, *args, **kwargs):
        
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self):
        self.a = 123


s1 = Singleton()
print(s1,id(s1))

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

"""
<__main__.Singleton object at 0x000001DA1999F9E8> 2036244019688
<__main__.Singleton object at 0x000001DA1999F9E8> 2036244019688
"""

2.2 方法二:metaclass

通过metaclass属性指定元类,控制类的实例化对象的创建。

元类指定单例类实例化时产生的对象为元类中的__instance属性对应的对象。

这样就可以使单例类每次实例化都为单例。

class Base(type):
    __instance = None
    
    def __call__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = super(Base, cls).__call__(*args, **kwargs)
        return cls.__instance

class Singleton(metaclass=Base):
    pass

s1 = Singleton()
s2 = Singleton()

print(s1,id(s1))
print(s2,id(s2))

"""
<__main__.Singleton object at 0x0000021AB8B9BC50> 2313791585360
<__main__.Singleton object at 0x0000021AB8B9BC50> 2313791585360
"""

2.3 方法三:装饰器

这也是方法1的升级(高级)版本。

这是一种更pythonic,更elegant的方法,单例类本身根本不知道自己是单例的,因为他本身(自己的代码)并不是单例的。

而装饰器使单例类每次都会返回一个单例对象罢了。

# 普通装饰器
def make_singleton(cls,*args,**kwargs):
    _instances = {}
    
    def singleton_class():
        if cls not in _instances:
            _instances[cls] = cls(*args,**kwargs)
        return _instances[cls]

    return singleton_class


@make_singleton
class Test:
    a = 1


s1 = Test()
s2 = Test()
print(s1,id(s1))
print(s2,id(s2))

'''
<__main__.Test object at 0x0000027515C614E0> 2701899732192
<__main__.Test object at 0x0000027515C614E0> 2701899732192
'''

# 第二种装饰器(强行用lambda函数)
def lambda_decorator(cls,*args,**kwargs):
    _instance = cls(*args,**kwargs)
    cls.__call__ = lambda _instance: _instance
    return _instance

@lambda_decorator
class Test:
    a = 1


s1 = Test()
s2 = Test()
print(s1,id(s1))
print(s2,id(s2))

'''
<__main__.Test object at 0x000002318C7F1550> 2411833791824
<__main__.Test object at 0x000002318C7F1550> 2411833791824
'''

2.4 方法四:共享属性

所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法)。

而恰好同一个类的所有实例天然拥有相同的行为(方法),所以只需要保证同一个类的所有实例具有相同的状态(属性)即可。

所有实例共享属性的最简单最直接的方法就是让__dict__属性指向(引用)同一个字典(dict),这样就可以让实例之间共享属性了。

这样做虽然对象并非真正的同一个对象(id不同),但是由于所有的对象属性与方法都相同,但也可以称作单例。

class Base:
    _dic = {}

    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls,*args, **kwargs)
        obj.__dict__ = cls._dic
        return obj

class Singleton(Base):
    pass

s1 = Singleton()
s1.name = "single"
s2 = Singleton()

print(s1,s1.__dict__)
print(s2,s2.__dict__)

'''
<__main__.Singleton object at 0x000001C462BD1550> {'name': 'single'}
<__main__.Singleton object at 0x000001C462BCAF60> {'name': 'single'}
'''
posted @ 2019-10-13 23:44  Donner  阅读(208)  评论(0编辑  收藏  举报