Python 實現單例模式

程序員歷來不缺對象,想 new 幾個就 new 幾個。程序員

對象.png

可是對象多了不免會出點問題,指不定哪天哪一個對象就爆炸了。單例模式就是爲了解決這個問題,不管 new 了幾回,都只能存在一個對象,相似一些網站的登陸,就是經過這種方式,實現只能有一個帳號登陸之類的功能。安全

首先能夠簡單地實現一下:網站

class Singleton(object):
    __instance = None

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

    @classmethod
    def get_instance(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = Singleton(*args, **kwargs)
        return cls.__instance


obj1 = Singleton.get_instance()
obj2 = Singleton.get_instance()

print(obj1)
print(obj2)

輸出以下,能夠看出兩個對象 obj1obj2 是同一個地址,即這個時候只有一個對象。spa

<__main__.Singleton object at 0x0000015F47A2CC88>
<__main__.Singleton object at 0x0000015F47A2CC88>

但這種方法不是線程安全的線程

import threading
import time


class Singleton(object):
    __instance = None

    def __init__(self, *args, **kwargs):
        time.sleep(1)

    @classmethod
    def get_instance(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = Singleton(*args, **kwargs)
        return cls.__instance


def task():
    obj = Singleton.get_instance()
    print(obj)


for i in range(6):
    threading.Thread(target=task).start()

輸出結果,出現了多個對象:code

<__main__.Singleton object at 0x0000028A133F1F48>
<__main__.Singleton object at 0x0000028A134C93C8>
<__main__.Singleton object at 0x0000028A134C9288>
<__main__.Singleton object at 0x0000028A134C9148>
<__main__.Singleton object at 0x0000028A134BEFC8>
<__main__.Singleton object at 0x0000028A134C9508>

並且上面這種方法只有第一次 get_instance() 的時候能給對象傳遞參數,總之有許多弊端。Python 提供了 __new__ 方法正好完美解決了這個問題,再加上鎖,就能實現一個線程安全的單例模式對象

import threading
import time


class Singleton(object):
    __lock = threading.Lock()
    __instance = None

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

    def __init__(self, *args, **kwargs):
        time.sleep(1)


def task():
    obj = Singleton()
    print(obj)


if __name__ == '__main__':
    for i in range(6):
        threading.Thread(target=task).start()

輸出結果:blog

<__main__.Singleton object at 0x000001DA4A1C0F88>
<__main__.Singleton object at 0x000001DA4A1C0F88>
<__main__.Singleton object at 0x000001DA4A1C0F88>
<__main__.Singleton object at 0x000001DA4A1C0F88>
<__main__.Singleton object at 0x000001DA4A1C0F88>
<__main__.Singleton object at 0x000001DA4A1C0F88>
相關文章
相關標籤/搜索