Python设计模式中单例模式的实现及在Tornado中的应用
单例模式的实现方式
将类实例绑定到类变量上
class Singleton(object):
_instance = None
def new(cls, *args):
if not isinstance(cls._instance, cls):
cls._instance = super(Singleton, cls).new(cls, *args)
return cls._instance
但是子类在继承后可以重写__new__以失去单例特性
class D(Singleton):
def new(cls, *args):
return super(D, cls).new(cls, *args)
使用装饰器实现
def singleton(_cls):
inst = {}
def getinstance(args, **kwargs):
if _cls not in inst:
inst[_cls] = _cls(args, **kwargs)
return inst[_cls]
return getinstance
@singleton
class MyClass(object):
pass
问题是这样装饰以后返回的不是类而是函数,当然你可以singleton里定义一个类来解决问题,但这样就显得很麻烦了
使用__metaclass__,这个方式最推荐
class Singleton(type):
_inst = {}
def call(cls, args, **kwargs):
if cls not in cls._inst:
cls._inst[cls] = super(Singleton, cls).call(args)
return cls._inst[cls]
class MyClass(object):
metaclass = Singleton
Tornado中的单例模式运用
来看看tornado.IOLoop中的单例模式:
class IOLoop(object):
@staticmethod
def instance():
"""Returns a global IOLoop instance.
Most applications have a single, global IOLoop running on the
main thread. Use this method to get this instance from
another thread. To get the current thread's IOLoop, use current().
"""
if not hasattr(IOLoop, "_instance"):
with IOLoop._instance_lock:
if not hasattr(IOLoop, "_instance"):
# New instance after double check
IOLoop._instance = IOLoop()
return IOLoop._instance
为什么这里要double check?来看个这里面简单的单例模式,先来看看代码:
class Singleton(object):
@staticmathod
def instance():
if not hasattr(Singleton, '_instance'):
Singleton._instance = Singleton()
return Singleton._instance
在 Python 里,可以在真正的构造函数__new__里做文章:
class Singleton(object):
def new(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).new(cls, *args, **kwargs)
return cls._instance
这种情况看似还不错,但是不能保证在多线程的环境下仍然好用,看图:
201632180733229.png (683×463)
出现了多线程之后,这明显就是行不通的。
1.上锁使线程同步
上锁后的代码:
import threading
class Singleton(object):
_instance_lock = threading.Lock()
@staticmethod
def instance():
with Singleton._instance_lock:
if not hasattr(Singleton, '_instance'):
Singleton._instance = Singleton()
return Singleton._instance
这里确实是解决了多线程的情况,但是我们只有实例化的时候需要上锁,其它时候Singleton._instance已经存在了,不需要锁了,但是这时候其它要获得Singleton实例的线程还是必须等待,锁的存在明显降低了效率,有性能损耗。
2.全局变量
在 Java/C++ 这些语言里还可以利用全局变量的方式解决上面那种加锁(同步)带来的问题:
class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
在 Python 里就是这样了:
class Singleton(object):
@staticmethod
def instance():
return _g_singleton
_g_singleton = Singleton()
def get_instance():
return _g_singleton
但是如果这个类所占的资源较多的话,还没有用这个实例就已经存在了,是非常不划算的,Python 代码也略显丑陋……
所以出现了像tornado.IOLoop.instance()那样的double check的单例模式了。在多线程的情况下,既没有同步(加锁)带来的性能下降,也没有全局变量直接实例化带来的资源浪费。
3.装饰器
如果使用装饰器,那么将会是这样:
import functools
def singleton(cls):
''' Use class as singleton. '''
cls.new_original = cls.new
@functools.wraps(cls.new)
def singleton_new(cls, *args, **kw):
it = cls.dict.get('it')
if it is not None:
return it
cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
it.__init_original__(*args, **kw)
return it
cls.new = singleton_new
cls.init_original = cls.init
cls.init = object.init
return cls
Sample use:
@singleton
class Foo:
def new(cls):
cls.x = 10
return object.new(cls)
def init(self):
assert self.x == 10
self.x = 15
assert Foo().x == 15
Foo().x = 20
assert Foo().x == 20
def singleton(cls):
instance = cls()
instance.call = lambda: instance
return instance
Sample use
@singleton
class Highlander:
x = 100
Of course you can have any attributes or methods you like.
Highlander() is Highlander() is Highlander #=> True
id(Highlander()) == id(Highlander) #=> True
Highlander().x == Highlander.x == 100 #=> True
Highlander.x = 50
Highlander().x == Highlander.x == 50 #=> True
Python设计模式中单例模式的实现及在Tornado中的应用的更多相关文章
- python设计模式之单例模式(一)
前言 单例模式是创建模式中比较常见和常用的模式,在程序执行的整个生命周期只存在一个实例对象. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python ...
- python设计模式之单例模式(二)
上次我们简单了解了一下什么是单例模式,今天我们继续探究.上次的内容点这 python设计模式之单例模式(一) 上次们讨论的是GoF的单例设计模式,该模式是指:一个类有且只有一个对象.通常我们需要的是让 ...
- python设计模式之单例模式(转)
设计模式之单例模式 单例设计模式是怎么来的?在面向对象的程序设计中,当业务并发量非常大时,那么就会出现重复创建相同的对象,每创建一个对象就会开辟一块内存空间,而这些对象其实是一模一样的,那么有没有办法 ...
- python设计模式之单例模式(一)
单例设计模式的概念: 单例设计模式即确保类有且只有一个特定类型的对象,并提供全局访问点.一般我们操作数据库的时候为了避免统一资源产生互相冲突,创建单例模式可以维护数据的唯一性. 单例模式的特性: 确保 ...
- Python设计模式之单例模式
1.由于语言的特性不同,设计模式的实现方式和实现难度也会不同 2.有的模式已经在语言内置了,比如迭代器模式. 3.单例模式可以直接用模块级变量来实现 4.普通工厂模式可以直接通过传入"类名& ...
- 【python 设计模式】单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. 比如,某 ...
- python 设计模式之 单例模式
单例模式是做为"全局变量"的替代品出现的.所以它具有全局变量的特点:全局可见.贯穿应用程序的整个生命期,保证在程序执行中,某个类仅仅存在一个实例,所以通常不希望类中的构造函数被调用 ...
- python 设计模式之单例模式 Singleton Pattern
#引入 一个类被设计出来,就意味着它具有某种行为(方法),属性(成员变量).一般情况下,当我们想使用这个类时,会使用new 关键字,这时候jvm会帮我们构造一个该类的实例.这么做会比较耗费资源. 如果 ...
- python设计模式之--单例模式
python的单例模式就是一个类的实例只能自始自终自能创建一次.应用场景比如说数据库的连接池. #!/usr/bin/env python # coding=utf- class Foo(object ...
随机推荐
- BMP图像直方图均衡算法(C语言大作业)
万丈高楼平地起 C语言大作业 一.学习笔记篇 1.学习MarkDown MarkDown注重写作本身,而非花俏的界面 编辑器:vscode 插件:Markdown,Markdown Preview 2 ...
- Java日期格式转换
Java时间格式转换大全 import java.text.*;import java.util.Calendar;public class VeDate {/** * 获取现在时间 * ...
- 【NuGet】使用NuGet打包并发布至ProGet过程 (步骤详细,附python脚本)【上篇】
一.基本知识 (1)NuGet : NuGet是一个为大家所熟知的Visual Studio扩展,通过这个扩展,开发人员可以非常方便地在Visual Studio中安装或更新项目中所需要的第三方组件, ...
- 【NOI2006】聪明的导游
[NOI2006]聪明的导游 题面 洛谷 题目描述 小佳最近迷上了导游这个工作,一天到晚想着带游客参观各处的景点.正好 M 市在举行 NOI,来参观的人特别的多.不少朋友给小佳介绍了需要导游的人. M ...
- 利用MailSniper越权访问Exchange邮箱
0x01 概述 Microsoft Exchange用户可以授权给其他用户对其邮箱文件夹进行各种级别的访问.例如,用户可以授予其他用户读取访问其收件箱中里面的电子邮件,但是要是用户(或Exchange ...
- POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化)
POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化) 题意分析 贴海报,新的海报能覆盖在旧的海报上面,最后贴完了,求问能看见几张海报. 最多有10000张海报,海报 ...
- 【学习笔记】ac自动机&fail树
定义 解决文本串和多个模式串匹配的问题: 本质是由多个模式串形成的一个字典树,由tie的意义知道:trie上的每一个节点都是一个模式串的前缀: 在trie上加入fail边,一个节点fail边指向这个节 ...
- Codeforces 895.C Square Subsets
C. Square Subsets time limit per test 4 seconds memory limit per test 256 megabytes input standard i ...
- linux python3获取ip地址
一.不带参数 #!/usr/bin/python # -*- coding: UTF-8 -*- import os def get_ip(): #注意外围使用双引号而非单引号,并且假设默认是第一个网 ...
- 类的起源与metaclass
一.概述 我们知道类可以实例化出对象,那么类本身又是怎么产生的呢?我们就来追溯一下类的起源. 二.类的起源 2.1 创建一个类 class Foo(object): def __init__(self ...