单例模式的实现方式

将类实例绑定到类变量上

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中的应用的更多相关文章

  1. python设计模式之单例模式(一)

    前言 单例模式是创建模式中比较常见和常用的模式,在程序执行的整个生命周期只存在一个实例对象. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python ...

  2. python设计模式之单例模式(二)

    上次我们简单了解了一下什么是单例模式,今天我们继续探究.上次的内容点这 python设计模式之单例模式(一) 上次们讨论的是GoF的单例设计模式,该模式是指:一个类有且只有一个对象.通常我们需要的是让 ...

  3. python设计模式之单例模式(转)

    设计模式之单例模式 单例设计模式是怎么来的?在面向对象的程序设计中,当业务并发量非常大时,那么就会出现重复创建相同的对象,每创建一个对象就会开辟一块内存空间,而这些对象其实是一模一样的,那么有没有办法 ...

  4. python设计模式之单例模式(一)

    单例设计模式的概念: 单例设计模式即确保类有且只有一个特定类型的对象,并提供全局访问点.一般我们操作数据库的时候为了避免统一资源产生互相冲突,创建单例模式可以维护数据的唯一性. 单例模式的特性: 确保 ...

  5. Python设计模式之单例模式

    1.由于语言的特性不同,设计模式的实现方式和实现难度也会不同 2.有的模式已经在语言内置了,比如迭代器模式. 3.单例模式可以直接用模块级变量来实现 4.普通工厂模式可以直接通过传入"类名& ...

  6. 【python 设计模式】单例模式

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

  7. python 设计模式之 单例模式

    单例模式是做为"全局变量"的替代品出现的.所以它具有全局变量的特点:全局可见.贯穿应用程序的整个生命期,保证在程序执行中,某个类仅仅存在一个实例,所以通常不希望类中的构造函数被调用 ...

  8. python 设计模式之单例模式 Singleton Pattern

    #引入 一个类被设计出来,就意味着它具有某种行为(方法),属性(成员变量).一般情况下,当我们想使用这个类时,会使用new 关键字,这时候jvm会帮我们构造一个该类的实例.这么做会比较耗费资源. 如果 ...

  9. python设计模式之--单例模式

    python的单例模式就是一个类的实例只能自始自终自能创建一次.应用场景比如说数据库的连接池. #!/usr/bin/env python # coding=utf- class Foo(object ...

随机推荐

  1. 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法

    题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...

  2. java垃圾回收 - 为什么要进行垃圾回收

    1.为什么要进行垃圾回收:      在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象 的内存时,该内存便 ...

  3. 【CodeChef PREFIXOR】Prefix XOR

    https://odzkskevi.qnssl.com/f0fbdb108ec813b1294f8f714805963b?v=1502083692 网上搜到的题解: http://blog.csdn. ...

  4. 洛谷P1273 有线电视网 【树上分组背包】

    题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从转播站到转播站以及从 ...

  5. 浴谷八连测R4题解

    一开始出了点bug能看见排行榜,于是我看见我半个小时就A掉了前两题,信心场QAQ T1字符串题就不说了qwq #include<iostream> #include<cstring& ...

  6. 解题:POI 2015 Pieczęć

    题面 发现好像没有什么好做法,那就模拟么=.= 以印章左上角的'x'为基准,记录印章上'x'的相对位置模拟.记录相对位置是因为可能有这种情况↓ 直接模拟是会漏掉的=.= #include<cst ...

  7. 将项目通过maven install到本地仓库后,Intellij中其他调用的项目无法引用该jar

    通常,我们会新建一个项目,其为其他项目添加公共的能力.其他项目可以引用其maven坐标来使用其提供的功能. 但最近做项目发现,修改了公共项目中的代码,并且使用mavan install将其jar安装到 ...

  8. Codeforces Round #299 (Div. 2)A B C 水 dfs 二分

    A. Tavas and Nafas time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  9. C++模板类注意事项

    最近使用C++模板,虽然工作几年了,但是模板用的很少,确切的说自己实现的机会很小. 昨天写了一个代码maxheap.h 中实现了类模板的声明,我将实现写在maxheap.cpp中, 当在main.cp ...

  10. 详解 Cookie 和 Session 关系和区别

    在技术面试中,经常被问到“说说Cookie和Session的区别”,大家都知道,Session是存储在服务器端的,Cookie是存储在客户端的,然而如果让你更详细地说明,你能说出几点?今天个推君就和大 ...