Python之单例模式

一、介绍

单例模式是一种常用的软件设计模式,属于创建型模式。单例模式的核心结构就是系统中一个类只有一个实例,保证了在程序的不同位置都可以且仅可以取到同一个对象实例。

应用场景:

1.单例模式广泛应用于各种开发场景:

游戏中需要有“场景管理器”这样一种东西,用来管理游戏场景的切换、资源载入、网络连接等等任务。这个管理器需要有多种方法和属性,在代码中很多地方会被调用,且被调用的必须是同一个管理器,否则既容易产生冲突,也会浪费资源

 

2.一些资源管理器常常设计成单例模式:

在计算机系统中,需要管理的资源包括软件外部资源,譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印机作业同时输出到打印机中。每台计算机可以有若干传真机卡,但是只应该有一个软件负责管理传真卡,以避免一个通信端口同时被两个请求同时调用。

需要管理的资源包括软件内部资源,譬如,大多数的软件都有一个(甚至多个)属性(properties)文件存放系统配置。这样的系统应当由一个对象来管理一个属性文件。

 

二、单例模式

1、常用的单例模式

class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):

        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance


s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # True

 

属性共用的单例

"""
上面的第一种写法,虽然创建的是同一个实例,
但是属性是不共用的,因为每次__init__都会重新设置
"""
class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

    def __init__(self, name, age):
        self.name = name
        self.age = age


s1 = Singleton(name="小明", age=18)
print(s1.name, s1.age)  # 小明 18

s2 = Singleton(name="小红", age=17)  # 这里相当于是重新赋值了name和age,之后的name age都是这个值
print(s2.name, s2.age)  # 小红 17

print(s1 is s2)  # True


"""
因此想要属性也共用,__init__也需要处理
"""
class Singleton(object):
    _instance = None
    _initialized = False

    def __new__(cls, *args, **kwargs):

        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

    def __init__(self, name, age):
        if not Singleton._initialized:
            self.name = name
            self.age = age
            Singleton._initialized = True


s1 = Singleton(name="小明", age=18)
print(s1.name, s1.age)  # 小明 18

s2 = Singleton(name="小红", age=17)
print(s2.name, s2.age)  # 小明 18

print(s1 is s2)  # True

 

加锁的单例

import time
import threading


class Singleton(object):
    lock = threading.RLock()  # 定义一把锁
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance:
            return cls._instance  # 如果之前实例化过,没必要再次实例化,因为都是同一个实例

        with cls.lock:  # 避免当线程没有返回实例前,另一个线程也进来了,导致出现不止一个实例
            if not cls._instance:
                cls._instance = super(Singleton, cls).__new__(cls)
            return cls._instance


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


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


time.sleep(10)
obj = Singleton()

 

2、函数单例装饰器

def singleton(cls):
    _instance = {}

    def _singleton(*args, **kwargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kwargs)

        return _instance[cls]

    return _singleton



@singleton
class A():
    def __init__(self, name):
        self.name = name

a1 = A("ming")
print(a1.name)  # ming

a2 = A("dong")
print(a2.name)  # ming

 

3、类单例装饰器

class Singleton(object):
    def __init__(self, cls):
        self._cls = cls
        self._instance = {}

    def __call__(self, *args, **kwargs):
        if self._cls not in self._instance:
            self._instance[self._cls] = self._cls(*args, **kwargs)

        return self._instance[self._cls]


@Singleton
class A():
    def __init__(self, name):
        self.name = name


a1 = A("ming")
print(a1.name)  # ming

a2 = A("dong")
print(a2.name)  # ming

 

4、使用 metaclass 实现单例模式

class Singleton(type):
    _instance = {}

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


class A(metaclass=Singleton):
    def __init__(self, name):
        self.name = name


a1 = A("ming")
print(a1.name)  # ming

a2 = A("dong")
print(a2.name)  # ming

 

posted @ 2022-01-08 21:08  我用python写Bug  阅读(425)  评论(0编辑  收藏  举报