Python 使用__new__方法实现单例

__new__方法实现单例模式

class SingletomCls:

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,"_instance"):
            cls._instance=super(SingletomCls, cls).__new__(cls)
        return cls._instance
     def __init__(self,*args,**kwargs):
        pass
 
 class Foo(SingletomCls):
    def __init__(self,name):
        self.name=name


ls=Foo("ls")
print(ls.name)

zs=Foo("zs")
print(ls.name)
print(zs.name)

代码打印结果:

ls
zs
zs

__new__实现的单例模式,可以实现重新初始化,因为控制单例的节点是在创建阶段,可以重新使用__init__进行初始化。

上面实现的单例,不是线程安全的。比如线程A,判断了没有实例,即not hasattr(cls,"_instance")为True,下一步让出CPU使用权给线程B。线程B,获得使用权,重新判断有无实例,无实例创建实例。然后A线程重新获得调度,继续去创建实例。造成系统中有多个实例存在。

写了个代码去验证这个线程不安全,为了夸大效果,在__new__里,有个等待时间。

import threading
import time
class SingletomCls:
    _single_lock=threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,"_instance"):
            time.sleep(5)
            cls._instance=super(SingletomCls, cls).__new__(cls)
        return cls._instance

    def __init__(self,*args,**kwargs):
        pass


class Foo(SingletomCls):
    def __init__(self,name):
        self.name=name

def task(args):
    obj=Foo("name_"+str(args))
    print(obj)


for i in range(10):
    t=threading.Thread(target=task,args=(i,))
    t.start()

结果:

<__main__.Foo object at 0x00000246E6636448>
<__main__.Foo object at 0x00000246E663C388>
<__main__.Foo object at 0x00000246E663C5C8><__main__.Foo object at 0x00000246E663C388><__main__.Foo object at 0x00000246E663C308>
<__main__.Foo object at 0x00000246E663C3C8><__main__.Foo object at 0x00000246E663C308>
<__main__.Foo object at 0x00000246CDDAFC48>
<__main__.Foo object at 0x00000246CDDC1348><__main__.Foo object at 0x00000246CDDAFC48>

可以发现,在这种多线程情况下,不能保证单例!

__new__方法实现带锁的单例模式

import threading

class SingletomCls:
    _single_lock=threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,"_instance"):
            with cls._single_lock:
                if not hasattr(cls,"_instance"):
                    cls._instance=super(SingletomCls, cls).__new__(cls)
        return cls._instance


    def __init__(self,*args,**kwargs):
        pass


class Foo(SingletomCls):
    def __init__(self,name):
        self.name=name

def task(args):
    obj=Foo("name_"+str(args))
    print(obj)

for i in range(10):
    t=threading.Thread(target=task,args=(i,))
    t.start()

打印的结果:

<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>
<__main__.Foo object at 0x00000223F4C61348>

多线程情况下,仍然只有一个实例存在

加入等待时间,验证效果:

import threading
import time
class SingletomCls:
    _single_lock=threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,"_instance"):
            time.sleep(5)
            with cls._single_lock:
                if not hasattr(cls,"_instance"):
                    cls._instance=super(SingletomCls, cls).__new__(cls)
        return cls._instance
        
    def __init__(self,*args,**kwargs):
        pass


class Foo(SingletomCls):
    def __init__(self,name):
        self.name=name

def task(args):
    obj=Foo("name_"+str(args))
    print(obj)

for i in range(10):
    t=threading.Thread(target=task,args=(i,))
    t.start()
<__main__.Foo object at 0x0000021B672BFC48><__main__.Foo object at 0x0000021B672BFC48><__main__.Foo object at 0x0000021B672BFC48>
<__main__.Foo object at 0x0000021B672BFC48>

<__main__.Foo object at 0x0000021B672BFC48>

<__main__.Foo object at 0x0000021B672BFC48><__main__.Foo object at 0x0000021B672BFC48><__main__.Foo object at 0x0000021B672BFC48><__main__.Foo object at 0x0000021B672BFC48>
<__main__.Foo object at 0x0000021B672BFC48>

可以看到加锁后确实能够保证单例模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值