python 单例模式全解

        Python 的单例实现方式有很多种,不同的需求下实现的需求也不一样,下面是一些我学习并用到的方案,也会将其有缺点写出。

第一种:使用__new__()的方式

class MyClass:
    _instance =None

    def __new__(cls,*args,**kwargs):
        if cls._instance is None:
            cls._instance = super(MyClass,cls).__new__(cls)
        return cls._instance
    
    def __init__(self) -> None:
        if not hasattr(self,'initialized'):#防止多次初始化
            self.initialized = True

if __name__=="__main__":
    m1 = MyClass()
    m2 = MyClass()
    print(id(m1) == id(m2))
    #输出True

但上面的实现方式并不能在多线程中使用,所以可以加个线程锁

import threading
class MyClass:
    _instance =None

    _lock = threading.Lock()

    def __new__(cls,*args,**kwargs):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(MyClass,cls).__new__(cls)
        return cls._instance
    
    def __init__(self) -> None:
        if not hasattr(self,'initialized'):#防止多次初始化
            self.initialized = True

if __name__=="__main__":
    m1 = MyClass()
    m2 = MyClass()
    print(id(m1) == id(m2))
    #输出True

更进一步,可以这样写 

import threading
class MyClass:
    _instance =None

    _lock = threading.Lock()

    def __new__(cls,*agrs,**kwargs):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super(MyClass,cls).__new__(cls)
        return cls._instance
    
    def __init__(self) -> None:
        if not hasattr(self,'initialized'):#防止多次初始化
            self.initialized = True

if __name__=="__main__":
    m1 = MyClass()
    m2 = MyClass()
    print(id(m1) == id(m2))
    #输出True

第二种:使用装饰器的方式

def singleton(cls):
    instance = {}
    def get_instance(*args,**kwargs):
        if cls not in instance:
            instance[cls] = cls(*args,**kwargs)
        return instance[cls]
    return get_instance 

@singleton
class MyClass:
    def __init__(self) -> None:
        pass

if __name__=="__main__":
    print(id(MyClass()) == id(MyClass()))
    #输出True

使用装饰器的方式实现单例模式时__init__()只会第一次创建对象时执行,如果需要每次获得对象时初始化对象就不要用该种实现方式,同时该实现方式也是线程安全的,因为GIL会阻止多线程进入装饰器,但如果是使用了多进程,该实现方式仍不是安全的,下面是加了线程锁的实现方式,在多进程中仍是安全的

import threading
import time

def singleton(cls):
    instance = {}
    lock = threading.Lock()
    def get_instance(*args,**kwargs):
        if cls not in instance:
            with lock:
                if cls not in instance:
                    instance[cls] = cls(*args,**kwargs)
        return instance[cls]
    return get_instance 

@singleton
class MyClass:
    def __init__(self) -> None:
        pass
if __name__=="__main__":
    print(id(MyClass()) == id(MyClass()))

第三种使用元类的方式

import threading

class Singleton(type):
    _instances = {}

    _lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            with cls._lock:
                if cls not in cls._instances:
                    cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class MyClass(metaclass=Singleton):
    def __init__(self):
        pass

if __name__=="__main__":
    print(id(MyClass()) == id(MyClass()))

使用这种方式创建单例模式,__init__(),也是只有第一次创建时会执行。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值