0
点赞
收藏
分享

微信扫一扫

Python--单例模式

小猪肥 2022-04-04 阅读 59

一、什么是单例模式

一个类,不断地实例化得到的对象,其实都是不同的对象

如果一个类实例化的对象永远是同一个对象的话,那么就可以称之为单例模式

比如,某个服务器的配置信息存在在一个文件中,客户端通过AppConfig类来读取配置文件的信息.

如果程序的运行的过程中,很多地方都会用到配置文件信息,则就需要创建很多的AppConfig实例,这样就导致内存中有很多AppConfig对象的实例,造成资源的浪费.其实这个时候AppConfig我们希望它只有一份,就可以使用单例模式.

二、实现单例模式的方法

2.1、使用模块

一个模块在第一次导入的时候,会执行模块代码,生成.pyc文件,当第二次导入的时候,就会直接加载.pyc文件。

我们把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了

新建一个python模块叫singleton,然后放入一个 py 文件,取名为 mysingleton.py
mysingleton.py

class Singleton(object):
    def foo(self):
        pass
singleton = Singleton()

使用

from singleton.mysingleton import singleton

这样,每次拿到的都是同一个对象

2.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():
    a = 1

    def __init__(self, x=0):
        self.x = x
        print('这是A的类的初始化方法')


a1 = A(2)
a2 = A(3)

print(a1.__dict__ ,a2.__dict__)
print(id(a1), id(a2))

在这里插入图片描述

2.3、调用类

思路就是, 调用类自定义的 _instance属性 , 这样有一个弊端就是在使用类创建的时候,并不是单例了.也就是说在创建类的时候一定要用类里面规定的方法创建

class Singleton(object):
    def __init__(self,*args,**kwargs):
        pass

    @classmethod
    def get_instance(cls, *args, **kwargs):
        # 利用反射,看看这个类有没有_instance属性
        if not hasattr(Singleton, '_instance'):
            Singleton._instance = Singleton(*args, **kwargs)

        return Singleton._instance


s1 = Singleton()  # 使用这种方式创建实例的时候,并不能保证单例
s3 = Singleton()
print(id(s1),id(s3))

s2 = Singleton.get_instance()  # 只有使用这种方式创建的时候才可以实现单例
s4 = Singleton.get_instance()
print(id(s2),id(s4))

在这里插入图片描述

这种方法过于复杂并不推荐使用

import time
import threading

class Singleton(object):
    _instance_lock = threading.Lock()

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

    @classmethod
    def get_instance(cls,*args,**kwargs):
        if not hasattr(Singleton,'_instance'):
            with Singleton._instance_lock:
                if not hasattr(Singleton,'_instance'):
                    Singleton._instance = Singleton(*args,**kwargs)

        return Singleton._instance

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

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

obj = Singleton.get_instance()
print(obj)

2.4、重写__new__方法

import threading


class Singleton(object):
    _instance_lock = threading.Lock()

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

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            with Singleton._instance_lock:
                if not hasattr(cls, '_instance'):
                    Singleton._instance = super().__new__(cls)

        return Singleton._instance


obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2)


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


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

相关推荐

0 条评论