单例模式是23种面向对象的设计模式之一。在实际应用中,涉及到配置或资源管理的对象,都应该考虑单例模式。广义上讲,只要能够保证只执行一次类的实例化过程,就能实现单例模式。如果某段代码确实只会执行一次,那么就是一个天然的单例模式,比如python里的模块导入。而有的时候,初始化对象的函数可能要执行多次,这时就需要对类的实例化进行拦截。单例模式最基本的问题,是判断是否类已经实例化,这就需要用一个变量,来判断,比如锁,全局变量,类变量(Python), 闭包(Python)等等。
1. Staticmethod/Classmethod
# 用类方法 类属性来实现 典型的tarnado模块 IOLoop
class IOLoop(object):
'''
some other code ...
'''
@staticmethod # 类方法装饰器
def instance():
"""Returns a global IOLoop instance.
Most single-threaded applications have a single, global IOLoop.
Use this method instead of passing around IOLoop instances
throughout your code.
A common pattern for classes that depend on IOLoops is to use
a default argument to enable programs with multiple IOLoops
but not require the argument for simpler applications::
class MyClass(object):
def __init__(self, io_loop=None):
self.io_loop = io_loop or IOLoop.instance()
"""
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
@staticmethod
def initialized():
"""Returns true if the singleton instance has been created."""
return hasattr(IOLoop, "_instance")
def install(self):
"""Installs this IOloop object as the singleton instance.
This is normally not necessary as `instance()` will create
an IOLoop on demand, but you may want to call `install` to use
a custom subclass of IOLoop.
"""
assert not IOLoop.initialized()
IOLoop._instance = self
2. __new__
# 使用__new__
class singleton1(object):
def __new__(cls, *args, **kwargs): #new拦截类的实例化
if not hasattr(cls, '_instance'):
print 'create instance here'
cls._instance = super(singleton1, cls).__new__(cls, *args, **kwargs)
return cls._instance
print singleton1()
print singleton1()
create instance here
<__main__.singleton1 object at 0x7f2ad40dacd0>
<__main__.singleton1 object at 0x7f2ad40dacd0>
关于new: new是用来创建对象的。拦截类的实例化,修改对象的属性,返回这个对象。new之后对象才存在,init只是修改类的属性
3.元类
# 使用metaclass, 生成类的类
class meta_single(type):
_instance = {}
# 这里要用__call__, 而不是__new__
def __call__(cls, *args, **kwargs):
if cls not in cls._instance:
print 'create instance here'
cls._instance[cls] = super(meta_single, cls).__call__(*args, **kwargs)
return cls._instance[cls]
class singleton2(object):
# __metaclass__拦截类的创建,而不是拦截实例化
__metaclass__ = meta_single # 在这里, 元类中的__new__方法和__init__方法其实已经被执行了
print singleton2()
print singleton2()
print isinstance(singleton2, meta_single)
print issubclass(singleton2, meta_single)
create instance here
<__main__.singleton2 object at 0x7f2ad4084c50>
<__main__.singleton2 object at 0x7f2ad4084c50>
True
False
关于元类:元类是用来生成类的(注意不是类的实例), 元类回拦截类的创建,修改类的属性,并返回这个类。可以理解为singleton2是meta_single的一个对象。 python3的语法略有不同。
4.装饰器 + 闭包
# 使用装饰器
from functools import wraps
def dec_single(cls):
instances = {} # 闭包
@wraps(cls)
def getinstance(*args, **kw):
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
@dec_single
class singleton3(object):
pass
print singleton3()
print singleton3()
<__main__.singleton3 object at 0x7f2accefb4d0>
<__main__.singleton3 object at 0x7f2accefb4d0>
这里用到了闭包,要注意一下
需要注意:
- 其实1,2,3都是利用了类属性来记录类是否实例化过。原理上是一样的。
- 以上都不是线程安全的