python单例设计模式_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

这种情况看似还不错,但是不能保证在多线程的环境下仍然好用,看图:

出现了多线程之后,这明显就是行不通的。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值