单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

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

如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例;

这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。

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

单例模式三个要点

  • 一是某个类只能有一个实例
  • 二是它必须自行创建这个实例
  • 三是它必须自行向整个系统提供这个实例

Python 中实现单例模式方法

  • 使用模块
  • 使用 __new__
  • 使用装饰器(decorator)
  • 使用元类(metaclass)

使用模块

其实,Python 的模块就是天然的单例模式

因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

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

1
2
3
4
5
#tests1.py
class MyClass(object):
    def foo(self):
        print('MyClass.foo')
my_class_obj=MyClass()

将上面的代码保存在文件 tests1.py 中,然后这样使用:

1
2
from .tests1 import my_class_obj
my_class_obj.foo()

使用 __new__

为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:

1
2
3
4
5
6
7
8
9
class MyClass(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(MyClass, cls).__new__(cls, *args, **kwargs)
        return cls._instance
 
class HerClass(MyClass):
    a = 1

在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance

执行情况如下:

1
2
3
4
5
one = HerClass()
two = HerClass()
print(one == two)   #True
print(one is two)   #True
print(id(one), id(two)) #42818864 42818864

使用装饰器

我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from functools import wraps
 
 
def singleton(cls):
    instances = {}
 
    @wraps(cls)
    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
 
    return getinstance
 
 
@singleton
class MyClass(object):
    a = 1

在上面,我们定义了一个装饰器 singleton,它返回了一个内部函数 getinstance,该函数会判断某个类是否在字典 instances 中;

如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]

使用 metaclass

元类(metaclass)可以控制类的创建过程,它主要做三件事:

  • 拦截类的创建
  • 修改类的定义
  • 返回修改后的类

使用元类实现单例模式的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Singleton(type):
    _instances = {}
 
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]
 
 
# Python2
# class MyClass(object):
#     __metaclass__ = Singleton
 
# Python3
class MyClass(metaclass=Singleton):
   pass

单例模式优点

实例控制

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

灵活性

因为类控制了实例化过程,所以类可以灵活更改实例化过程。

单例模式缺点

开销

虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

可能的开发混淆

使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用 new关键字实例化对象。
因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。
在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。

补充:元类(metaclass)

点击查看

Python中单例模式的使用方法的更多相关文章

  1. Python 中单例模式 4种方法

    假设我们在一个与数据库交互的系统中,需要进行数据库操作,那么我们就有必要了解单例模式,单例模式使得我们不用每次进行数据库的操作时都去链接数据库. 我将循环渐进,由浅入深的写一下单例模式示例. 实例1: ...

  2. python中List的sort方法的用法

    python列表排序 简单记一下python中List的sort方法(或者sorted内建函数)的用法. 关键字: python列表排序 python字典排序 sorted List的元素可以是各种东 ...

  3. 【转】python中List的sort方法(或者sorted内建函数)的用法

    原始出处:http://gaopenghigh.iteye.com/blog/1483864 python列表排序 简单记一下python中List的sort方法(或者sorted内建函数)的用法. ...

  4. 【转】关于python中re模块split方法的使用

    注:最近在研究文本处理,需要用到正则切割文本,所以收索到了这篇文章,很有用,谢谢原作者. 原址:http://blog.sciencenet.cn/blog-314114-775285.html 关于 ...

  5. 查看python中模块的所有方法

    查看python中模块的所有方法     安装的python模块,现将查看方法总结如下 一.CMD命令行下使用pydoc命令 在命令行下运行$ pydoc modules即可查看 二.在python交 ...

  6. PySpark 的背后原理--在Driver端,通过Py4j实现在Python中调用Java的方法.pyspark.executor 端一个Executor上同时运行多少个Task,就会有多少个对应的pyspark.worker进程。

    PySpark 的背后原理 Spark主要是由Scala语言开发,为了方便和其他系统集成而不引入scala相关依赖,部分实现使用Java语言开发,例如External Shuffle Service等 ...

  7. python中requests库使用方法详解

    目录 python中requests库使用方法详解 官方文档 什么是Requests 安装Requests库 基本的GET请求 带参数的GET请求 解析json 添加headers 基本POST请求 ...

  8. 全面了解python中的类,对象,方法,属性

    全面了解python中的类,对象,方法,属性 python中一切皆为对象,所谓对象:我自己就是一个对象,我玩的电脑就是对象,坐着的椅子就是对象,家里养的小狗也是一个对象...... 我们通过描述属性( ...

  9. python中列表元素连接方法join用法实例

    python中列表元素连接方法join用法实例 这篇文章主要介绍了python中列表元素连接方法join用法,实例分析了Python中join方法的使用技巧,非常具有实用价值,分享给大家供大家参考. ...

随机推荐

  1. Commons-VFS 使用SFTP

    http://pro.ctlok.com/2011/06/apache-commons-vfs-for-sftp.html

  2. Codeforces 476C Dreamoon and Sums (水

    题目链接:点击打开链接 题意: 给定a,b 对于一个数x.若x是nice number,则满足(x/b)/(x%b) == [1,a](即结果在1-a之间) 问: 输出一个数表示 全部nice num ...

  3. 【JavaScript】JavaScript DOM 编程

    在开发的时候,最主要是对DOM进行操作.DOM:Document Object Model 文本对象模型. DOM能够以一种独立于平台和语言的方式訪问和改动一个文档的内容和结构. DOM是针对xml( ...

  4. 解决js下跳转无referer的方法

    HTTP Header referer这玩意主要是告诉人们我是从哪儿来的,就是告诉人家我是从哪个页面过来的,可以用于统计访问本网站的用户来源,也可以用来防盗链.获取这个东西最好的方式是js,如果在服务 ...

  5. 121. Best Time to Buy and Sell Stock【easy】

    121. Best Time to Buy and Sell Stock[easy] Say you have an array for which the ith element is the pr ...

  6. 当synchronized关键字和this关键字

    package cn.itcast_01_mythread.thread.testThread; public class MyThreadWithImpliment_Synch_method imp ...

  7. IRQ与FIQ的区别

    1.对FIQ你必须进快处理中断请求,并离开这个模式. 2.IRQ可以被FIQ所中断,但FIQ不能被IRQ所中断,在处理FIQ时必须要关闭中断. 3.FIQ的优先级比IRQ高. 4.FIQ模式下,比IR ...

  8. IOS设计模式的六大设计原则之依赖倒置原则(DIP,Dependence Inversion Principle)

    定义 高层模块不应该依赖于低层模块,二者都应该依赖于抽象:抽象不应该依赖细节:细节应该依赖抽象. 定义解读 依赖倒置原则在程序编码中经常运用,其核心思想就是面向接口编程,高层模块不应该依赖低层模块(原 ...

  9. opus 规范 与参数解析

    bytestream_put_buffer(&p, "OpusHead", 8); bytestream_put_byte(&p, 1); /* Version * ...

  10. with root cause 解决办法

    现象:1.工程在启动的时候无异常,当页面加载到包含spring:message标签的页面时,在后台报空指针异常,同时控制               台会显示with root cause提示: 2. ...