单例模式是一种程序设计的方法,我理解单例模式:某个进程在生命周期内某类只存在一个实例对象,使用场景例如logger,配置模块,数据库连接池等,单实例可以减少资源使用,保证唯一性。
使用模块实现
最简单实现单实例:模块化,python解释器当import一个py文件时都会把该文件编码为pyc流,当再次import就直接读取pyc文件,除非py文件内容有所更改才会再次编码:建立一个singleton.py文件,在文件中实例化singleton类,这样就实现了单例。优点是简单,但不灵活。
# *_* coding: utf-8 *_*
class singleton(object):
pass
singleton = singleton()
使用__new__,metaclass
使用__new__这个魔术方法主要是在类初始化时进行控制。魔术方法可以理解为python代码和解释器的一种规约,python类在实例化时首先调用__new__去创建一个对象再__init__去初始化这个new出来的对象,所以__new__这个方法必须返回一个对象。当类中没有显式定义__new__方法时会调用父类中的__new__方法。所以要实现单例可以显式定义__new__方法:
# *_* coding: utf-8 *_*
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
def __init__(self):
pass
#这里有个问题,如果实例化singleton采用多线程就会产生两个线程同时执行
#cls._instance = super(singleton, cls).__new__(cls, *args, **kwargs)的可能,所以针对多线程进行加锁,
#python中锁不用理会怎么造和创造者,拿起来就可以“咔擦”进行加锁.
import threading
class singleton(object):
_instance_lock = threading.Lock() #建立一把锁
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
with singleton._instance_lock: #使用锁,with内部代码同时只能一个线程执行
cls._instance = super(singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
python中一切皆对象,无论我们定义一个str,int或者list都是实例化了一类。就算我们定义一个类它也是元类的实例。没显式定义父类的类都会继承object类,没显式定义元类的类都会继承type。当python解释器扫描到代码中的class A,就会调用该类的元类的__new__在内存中实例化元类的一个实例,我们实例化类A时就会调用元类的__call__方法。所以元类可以拦截类的创建并对类进行修改。元类实现单实例和__new__异曲同工:
# *_* coding: utf-8 *_*
class Meta(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Meta, cls).__call__(cls, *args, **kwargs)
return cls._instance
#多线程安全模式
import threading
class Meta(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
with Meta._instance_lock:
cls.instance = super(Meta, cls).__call__(cls, *args, **kwargs)
return cls._instance
#实现单实例的类需要继承Meta元类
#python 2
class singleton(object):
__metaclass__ = Meta
#python 3
class singleton(metaclass=Meta):
pass
使用装饰器
# *_* coding: utf-8 *_*
def dec(cls):
_instance = {}
def indec(*args, **kwargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs)
return _instance[cls]
return indec
#单实例实现方式,主要是在创建类时利用闭包原理把_instance封装在类外面,如下代码实例化singleton时候实际是调用indec函数
@dec
class singleton(object):
pass
#多线程同
总结
1.如果没有特别需求,用模块实现单实例方便又简单
2.如果有多个类需要实现单实例可以使用修饰器
3.如果有功能能上的特别定制需求才考虑使用__new__
4.metaclass设计是给非一般的人使用的,一般是不用-_-