最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

Python设计模式中单例模式的实现及在Tornado中的应用

来源:动视网 责编:小采 时间:2020-11-27 14:35:36
文档

Python设计模式中单例模式的实现及在Tornado中的应用

Python设计模式中单例模式的实现及在Tornado中的应用:单例模式的实现方式 将类实例绑定到类变量上 class Singleton(object): _instance = None def __new__(cls, *args): if not isinstance(cls._instance, cls): cls._instance = super(Singleton, cls).__
推荐度:
导读Python设计模式中单例模式的实现及在Tornado中的应用:单例模式的实现方式 将类实例绑定到类变量上 class Singleton(object): _instance = None def __new__(cls, *args): if not isinstance(cls._instance, cls): cls._instance = super(Singleton, cls).__
 单例模式的实现方式
将类实例绑定到类变量上

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

文档

Python设计模式中单例模式的实现及在Tornado中的应用

Python设计模式中单例模式的实现及在Tornado中的应用:单例模式的实现方式 将类实例绑定到类变量上 class Singleton(object): _instance = None def __new__(cls, *args): if not isinstance(cls._instance, cls): cls._instance = super(Singleton, cls).__
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top