iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python 中用多种方式实现单例模式
  • 438
分享到

Python 中用多种方式实现单例模式

Python实现单例模式Python单例模式 2022-11-16 00:11:39 438人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录使用模块使用装饰器使用类基于 __new__ 方法实现基于 metaclass 方式实现单例模式(Singleton Pattern) 是一种常用的

单例模式(Singleton Pattern) 是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。

事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

python 中,我们可以用多种方法来实现单例模式:

  • 使用模块
  • 使用装饰器
  • 使用类
  • 基于 __new__ 方法实现
  • 基于 metaclass 方式实现

下面来详细介绍:

使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。

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

如果我们真的想要一个单例类,可以考虑这样做:

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

将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象

from mysingleton import singleton

使用装饰器

def Singleton(cls):
    _instance = {}
 
    def _singleton(*args, **kargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kargs)
        return _instance[cls]
 
    return _singleton
 
 
@Singleton
class A(object):
    a = 1
 
    def __init__(self, x=0):
        self.x = x
 
 
a1 = A(2)
a2 = A(3)

使用类

class Singleton(object):
 
    def __init__(self):
        pass
 
    @claSSMethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance

一般情况,大家以为这样就完成了单例模式,但是当使用多线程时会存在问题:

class Singleton(object):
 
    def __init__(self):
        pass
 
    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance
 
import threading
 
def task(arg):
    obj = Singleton.instance()
    print(obj)
 
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()

程序执行后,打印结果如下:

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

看起来也没有问题,那是因为执行速度过快,如果在 __init__ 方法中有一些 io 操作,就会发现问题了。

下面我们通过 time.sleep 模拟,我们在上面 __init__ 方法中加入以下代码:

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

重新执行程序后,结果如下:

<__main__.Singleton object at 0x034A3410>
<__main__.Singleton object at 0x034BB990>
<__main__.Singleton object at 0x034BB910>
<__main__.Singleton object at 0x034ADED0>
<__main__.Singleton object at 0x034E6BD0>
<__main__.Singleton object at 0x034E6C10>
<__main__.Singleton object at 0x034E6B90>
<__main__.Singleton object at 0x034BBA30>
<__main__.Singleton object at 0x034F6B90>
<__main__.Singleton object at 0x034E6A90>

问题出现了!按照以上方式创建的单例,无法支持多线程

解决办法:加!未加锁部分并发执行,加锁部分串行执行,速度降低,但是保证了数据安全

import time
import threading
class Singleton(object):
    _instance_lock = threading.Lock()
 
    def __init__(self):
        time.sleep(1)
 
    @classmethod
    def instance(cls, *args, **kwargs):
        with Singleton._instance_lock:
            if not hasattr(Singleton, "_instance"):
                Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance
def task(arg):
    obj = Singleton.instance()
    print(obj)
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)

打印结果如下:

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

这样就差不多了,但是还是有一点小问题,就是当程序执行时,执行了 time.sleep(20) 后,下面实例化对象时,此时已经是单例模式了。

但我们还是加了锁,这样不太好,再进行一些优化,把 intance 方法,改成下面这样就行:

@classmethod
def 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
@classmethod
def 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

这样,一个可以支持多线程的单例模式就完成了。+

import time
import threading
 
 
class Singleton(object):
    _instance_lock = threading.Lock()
 
    def __init__(self):
        time.sleep(1)
 
    @classmethod
    def 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.instance()
    print(obj)
    
    
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()
    
    
time.sleep(20)
obj = Singleton.instance()
print(obj)

这种方式实现的单例模式,使用时会有限制,以后实例化必须通过 obj = Singleton.instance()

如果用 obj = Singleton(),这种方式得到的不是单例。

基于 __new__ 方法实现

通过上面例子,我们可以知道,当我们实现单例时,为了保证线程安全需要在内部加入锁。

我们知道,当我们实例化一个对象时,是先执行了类的 __new__ 方法(我们没写时,默认调用 object.__new__),实例化对象;然后再执行类的 __init__ 方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式。

import threading
class Singleton(object):
    _instance_lock = threading.Lock()
 
    def __init__(self):
        pass
 
 
    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = object.__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()

打印结果如下:

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

采用这种方式的单例模式,以后实例化对象时,和平时实例化对象的方法一样 obj = Singleton() 。

基于 metaclass 方式实现

相关知识:

类由 type 创建,创建类时,type 的 __init__ 方法自动执行,类() 执行 type 的 __call__ 方法(类的 __new__ 方法,类的 __init__ 方法)

对象由类创建,创建对象时,类的 __init__ 方法自动执行,对象()执行类的 __call__ 方法

例子:

class Foo:
    def __init__(self):
        pass
 
    def __call__(self, *args, **kwargs):
        pass
 
obj = Foo()
# 执行type的 __call__ 方法,调用 Foo类(是type的对象)的 __new__方法,用于创建对象,然后调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。
 
obj()    # 执行Foo的 __call__ 方法    

元类的使用:

class SingletonType(type):
    def __init__(self,*args,**kwargs):
        super(SingletonType,self).__init__(*args,**kwargs)
 
    def __call__(cls, *args, **kwargs): # 这里的cls,即Foo类
        print('cls',cls)
        obj = cls.__new__(cls,*args, **kwargs)
        cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
        return obj
 
class Foo(metaclass=SingletonType): # 指定创建Foo的type为SingletonType
    def __init__(self,name):
        self.name = name
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)
 
obj = Foo('xx')

实现单例模式:

import threading
 
class SingletonType(type):
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance
 
class Foo(metaclass=SingletonType):
    def __init__(self,name):
        self.name = name
obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)

 

--结束END--

本文标题: Python 中用多种方式实现单例模式

本文链接: https://www.lsjlt.com/news/172966.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python 中用多种方式实现单例模式
    目录使用模块使用装饰器使用类基于 __new__ 方法实现基于 metaclass 方式实现单例模式(Singleton Pattern) 是一种常用的...
    99+
    2022-11-16
    Python实现单例模式 Python单例模式
  • C#实现单例模式的多种方式
    什么是单例模式 这里我就不做过多的解释了, 毕竟关于Singleton的资料实在是太多太多了。点击这里 简单的思路就是, 创建对象单例的动作转移到另外的行为上面, 利用一个行为去创建...
    99+
    2024-04-02
  • Python实现单例模式的四种方式详解
    简介:单例模式可以保证一个类仅有一个实例,并提供一个访问它的全局访问点。适用性于当类只能有一个实例而且客户可以从一个众所周知的访问点访问它,例如访问数据库、MQ等。 实现方式: 1、...
    99+
    2024-04-02
  • 分析java中全面的单例模式多种实现方式
    目录一、单例模式的思想二、单例模式的 N 种实现方式2.1、饿汉式(线程安全,可用)2.2、常量式(线程安全,可用)2.3、懒汉式(线程不安全,并发场景不可用)2.4、同步的懒汉式?...
    99+
    2024-04-02
  • Android 单例模式的四种实现方式
    目录一.饿汉式二.懒汉式三.双重检查加锁方式四.静态内部类方式总结一.饿汉式 public class SingletionStarving { private sta...
    99+
    2024-04-02
  • Java单例模式的五种实现方式
    目录前言饿汉单例懒汉单例非线程安全的懒汉单例加同步锁的懒汉单例双重检验懒汉单例静态内部类静态内部类为什么是线程安全总结前言 单例模式(Singleton Pattern)是 Java...
    99+
    2024-04-02
  • Python中单例模式的实现方法
    单例 — 让 类 创建的对象,在系统中 只有唯一的一个实例; 1)、定义一个类属性,初始值是 None ,用于记录 单例对象的引用;2)、重写 new 方法;3)、如果 ...
    99+
    2024-04-02
  • Java单例模式的6种实现方式详解
    目录为什么使用单例模式使用单例模式需要注意的关键点单例模式的几种写法1. 饿汉式2. 懒汉式3. DCL(Double CheckLock)实现单例4. 静态内部类5...
    99+
    2024-04-02
  • 一文详解Python中实现单例模式的几种常见方式
    目录Python 中实现单例模式的几种常见方式元类(Metaclass):装饰器(Decorator):模块(Module):new 方法:Python 中实现单例模式的几种常见方式...
    99+
    2023-03-22
    Python 单例模式 Python 单例
  • Python实现单例模式
    1.什么是单例? 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。那么单例模式有什么用途呢?举个常见的单例模式例子,我们平时使用的电脑上都有一个回收站,在整个操作系统中,回...
    99+
    2023-01-31
    模式 Python
  • JS实现单例模式的N种方案
    目录JS实现单例模式的多种方案单例模式的概念方式1方式2方式3方式4方式5方式6JS实现单例模式的多种方案 ,本文稍加总结,列出了6种方式与大家分享,大体上将内容分为了ES5(Fun...
    99+
    2024-04-02
  • Python实现单例模式的方式是什么
    本篇内容介绍了“Python实现单例模式的方式是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!单例模式(Singleton Patter...
    99+
    2023-07-04
  • Python实现单例模式的方式有哪些
    这篇“Python实现单例模式的方式有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python实现单例模式的方式有哪些...
    99+
    2023-06-30
  • Python模拟登录多种实现方式
    Python模拟登录多种实现方式 基于Python 3.6 #coding:utf-8 import sys import io import urllib.request import http.cookiejar #####...
    99+
    2023-01-31
    多种 方式 Python
  • Python中怎么实现单例模式
    本文小编为大家详细介绍“Python中怎么实现单例模式”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python中怎么实现单例模式”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。...
    99+
    2024-04-02
  • python单例模式之seleniumdriver实现单例
    目录一、使用装饰器实现单例二、web自动化driver实现单例模式2.1 编写单例模式的装饰器2.2 driver 使用装饰器,实现单例模式2.3 获取driver的实例,就是单例了...
    99+
    2024-04-02
  • Python中实现单例模式的常见方式有哪些
    Python 中实现单例模式的几种常见方式元类(Metaclass):class SingletonType(type): """ 单例元类。用于将普通类转换为单例类。 "&q...
    99+
    2023-05-14
    Python
  • Python实现单例模式的五种写法总结
    目录使用模块使用装饰器基于 __new__ 方法实现基于 metaclass 方式实现单例模式(Singleton Pattern) 是一种常用的软件设计模式,该模式的主要目的是确保...
    99+
    2024-04-02
  • 在Python中如何实现单例模式
    本篇内容主要讲解“在Python中如何实现单例模式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“在Python中如何实现单例模式”吧!方法一:使用装饰器实现单例模式。from functools...
    99+
    2023-06-01
  • C++单例模式的几种实现方法详解
    目录局部静态变量方式静态成员变量指针方式智能指针方式辅助类智能指针单例模式通用的单例模板类总结局部静态变量方式 //通过静态成员变量实现单例 //懒汉式 class Single2 ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作