python中实现单例模式

单例模式的目的是一个类有且只有一个实例对象存在,比如在复用类的过程中,可能重复创建多个实例,导致严重浪费内存,此时就适合使用单例模式。

前段时间需要用到单例模式,就称着机会在网上找了找,有包含了__new__方法在内的5种单例模式,就顺便记录于此。


基于模块导入机制的实现

第一次执行程序时编译为.pyc文件,而第二次执行时会直接执行.pyc。基于此机制,可以通过把类和所创建的实例单独写在某模块内,在使用时直接从这么模块中导入即可,这个导入的实例对象即唯一对象。

# test.py文件
class Test(object):
    pass
# 创建实例对象
t = Test()

# 在其他文件中
from test import t

基于装饰器的实现

def singleton(cls):
    instance = None

    def wrap(*argrs, **kwargs):
        nonlocal instance
        if instance is None:
            instance = cls(*args, **kwargs)
        return instance

    return wrap

@singleton
class Test(object):

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

t1 = Test()
t2 = Test()
print(t1 is t2)  # 输出True

基于类(类方法)的实现(这个看别人的博客学来的)

class Test(object):

    def __init__(self):
        pass

    
    @classmethod
    def instance(cls, *args, **kwargs):     # 每次调用此类方法即可创建实例对象
        if not hasattr(Test, "_instance"):
            Test._instance = Test(*args, **kwargs)
        return Test._instance

上述的实现方法在使用多线程时会出现问题,即这种上述实现单例模式不支持多线程

import threading
import time

class Test(object):

    def __init__(self):
        time.sleep(2)

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Test, "_instance"):
            Test._instance = Test(*args, **kwargs)
        return Test._instance

def task(args):
    obj = Test.instance()
    print(obj)

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

注意,如果上述不用sleep()暂停,执行速度过快时,仍可能存在相同地址

解决方法:加锁

import threading
import time

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

    def __init__(self):
        time.sleep(2)

    @classmethod
    def instance(cls, *args, **kwargs):
        with Test._instance_lock:
            if not hasattr(Test, "_instance"):
                Test._instance = Test(*args, **kwargs)
        return Test._instance

def task(args):
    obj = Test.instance()
    print(obj)

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

# 检查长时间后是否为单例
time.sleep(20)
obj = Test.instance()
print(obj)

上述方案长时间后虽然仍为单例模式,但是仍处于加锁的状态,可通过将锁的位置放在判断实例是否存在之后,如果不存在需要重新创建时再加锁

@classmethod
def instance(cls, *args, **kwargs):
    if not hasattr(Test, "_instance"):
        with Test._instance_lock:
            Test._instance = Test(*args, **kwargs)
    return Test._instance          

上述这种方法的问题在于创建实例对象时是通过调用Test.instance()创建的,而不是常规那样创建

基于__new__方法的实现(最常见)

在创建一个实例对象时,先调用__new__方法,再调用__init__方法

import threading
import time
class Test(object):

    def __init__(self):
        time.sleep(1)

    def __new__(cls, *args, **kwargs):
        if not hasattr(Test, "_instance"):
            Test._instance = object.__new__(cls)  # 相当于继承
        return Test._instance

obj1 = Test()
obj2 = Test()
print(obj1, obj2)

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

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

也可像之前装饰器一样用一个类属性来判断是否已有创建好的实例对象,如果没有则在__new__中创建,注意必须返回实例对象

这种方法不受线程影响

基于元类方法的实现

python中是类由type创建,在创建时类时会先调用type的__init__方法,然后创建实例对象时会调用type的__call__方法

顺序如下:type的__init__方法(创建类) -> type的__call__方法(类创建实例对象) -> 类的__new__方法(类创建实例对象) -> 类的__init__方法(类初始化实例对象)

元类的使用方式就是写一个继承了type的类,然后在我们所需的类中指定元类(通过metaclass参数),而继承了type的类则可重新定义类的构造函数,单例模式则可在__call__方法中定义

class SingletonType(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

class Test(metaclass=SingletonType):
    def __init__(self):
        pass

obj1 = Test()
obj2 = Test()
print(obj1,obj2)

注意:在元类中__call__的参数cls指所创建的类

原文地址:https://www.cnblogs.com/eat-w/p/12071005.html

时间: 2024-08-30 10:47:07

python中实现单例模式的相关文章

python中的单例模式

原文:https://segmentfault.com/a/1190000008141049 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. 比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息.如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig

Python中的单例模式的几种实现方式的优缺点及优化

单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. 比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息.如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪

Python中的单例模式——装饰器实现剖析

Python中单例模式的实现方法有多种,但在这些方法中属装饰器版本用的广,因为装饰器是基于面向切面编程思想来实现的,具有很高的解耦性和灵活性. 单例模式定义:具有该模式的类只能生成一个实例对象. 先将代码写上 #创建实现单例模式的装饰器 1 def singleton (cls, *args, **kwargs): 2 instances = {} 3 def get_instance (*args, **kwargs): 4 if cls not in instances: 5 instanc

Python中的单例模式的几种实现方式的及优化

阅读目录(Content) 单例模式 实现单例模式的几种方式 1.使用模块 2.使用装饰器 3.使用类 4.基于__new__方法实现(推荐使用,方便) 5.基于metaclass方式实现 相关知识 实现单例模式 回到顶部(go to top) 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. 比如,某个服务器程序的配置信息存放在一个文件中,客户

Python 中的单例模式

1.什么是单例模式   单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场.单例模式能控制一个类只能产生一个对象. 2.为什么需要单例模式 当每个实例都会占用资源,而且实例初始化会影响性能,这个时候就可以考虑使用单例模式,它给我们带来的好处是只有一个实例占用资源,并且只需初始化一次: 当有同步需要的时候,可以通过一个实例来进行同步控制,比如对某个共享文件(如日

Python中的单例模式的几种实现方式和优化以及pyc文件解释(转)

原文:https://www.cnblogs.com/huchong/p/8244279.html 另一篇关于.pyc文件是什么?  原文: http://blog.sina.com.cn//s/blog_17bce02530102ya3k.html 一:什么是pyc文件? pyc文件就是 py程序编译后得到的文件,是一种二进制文件.一般是这样的: pyc文件经过python解释器最终会生成机器码运行.所以pyc文件是可以跨平台部署的,类似Java的.class文件.如果py文件改变,也会重新生

python中对单例模式的理解

class Foo(object): instance = None def __init__(self): pass def process(self): return '1234565' @classmethod #版本1单例模式 def get_instance(cls): if Foo.instance: return Foo.instance else: Foo.instance = Foo() return Foo.instance obj1 = Foo() print(obj1.p

转--python 中写单例

原文地址 原文地址2 Python中的单例模式的几种实现方式的及优化 阅读目录(Content) 单例模式 实现单例模式的几种方式 1.使用模块 2.使用装饰器 3.使用类 4.基于__new__方法实现(推荐使用,方便) 5.基于metaclass方式实现 相关知识 实现单例模式 回到顶部(go to top) 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对

深刻理解Python中的元类(metaclass)以及元类实现单例模式

深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例模式的那一节有些疑惑.因此花了几天时间研究下元类这个概念.通过学习元类,我对python的面向对象有了更加深入的了解.这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解