什么是单例模式?
简单来讲,单例模式是一种设计模式,在实例化过程中,确保类有且只有一个特定类型的对象,并提供全局访问点。一般应用于日志记录、数据库操作等情形,这些情形的特点是:程序运行过程中只能生成一个实例,以避免对同一资源产生相互冲突的请求。
概况来说,单例模式有如下特点:
- 确保类只有一个对象被创建
- 为对象提供一个访问点,使程序可以全局访问该对象
- 控制共享资源的并行访问
Python单例模式的实现方法
想要实现单例模式,常见的方法是将构造方法私有化,并创建一个静态方法来完成对象的初始化。而在Python中,由于无法创建私有的构造方法,通常需要完成以下两步:
- 只允许类生成一个实例
- 如果有实例了,则会重复提供同一个实例
代码实现:
class Singleton(object):
def __new__(cls):
if not hasattr(cls, "instance")
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
single = Singleton()
single1 = Singleton()
print("I am single ", single)
print("I am single1 ", single1)
# 结果为
# I am single <__main__.Singleton object at 0X102078ba8>
# I am single1 <__main__.Singleton object at 0X102078ba8>
通过重写__new__
方法,控制python
对象的创建。对象single和single1都是通过__new__
方法创建的,执行过程中会先检查对象是否已存在,如果存在则优先分配已存在的实例对象。
懒实例化的单例模式
有些时候,当导入模块时,我们可能会无意中创建一个对象,而此时根本用不到这个对象。类似懒加载,懒实例化确保我们在真正需要使用对象时才进行创建。
举个栗子:
class Singleton(object):
__instance = None
def __init__(self):
if not Singleton.__instance:
print("initial now")
else:
print("instance exist", self.getInstance())
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance
single = Singleton()
# 类初始化,但没有创建对象
print("object create now:", single.getInstance())
# 创建对象
single1 = Singleton()
# 对象已创建,使用同一对象
在首次实例化时,调用了__init__
方法,但并没有创建实例。真正创建对象是在getInstance
方法调用时,如此一来便可以在使用时进行真正的创建。
模块级别的单例模式
Python中,导入机制通过如下方式来工作:
- 检查一个python模块是否已经导入
- 如果已经导入,则返回该模块对象;如果没导入,则导入该模块并实例化
- 当模块首次被导入时会进行初始化,而再次导入时就不再初始化,而是返回同一个对象
由此可见,python可以通过导入模块的方式可以实现单例模式。
状态级别的单例模式(单态模式)
我们通常所说的单例模式,指的是一个类有且只有一个对象。但另一种说法指出,有些时候程序中需要关注的是对象的状态,而非同一性。这种模式也被称作单态模式。
举个栗子:
class Brog:
__shared_state = {"1" : "2"}
def __init__(self):
self.x = 1
slef.__dict__ = self.__shared_state
b = Brog()
b1 = Brog()
b.x = 4
print(b)
print(b1)
print(b.__dict__)
print(b1.__dict__)
# 执行结果显示,b和b1不是同一个对象,但当对象b改变自身属性时,b1的状态也被改变
首先通过将类变量__shared_state
赋值给__dict__
,而python使用__dict__
存储一个类所有对象的状态。把类变量__shared_state
赋值给所有已创建的实例,这样当创建两个实例b和b1时,将得到两个不同的对象。而对象的状态则是相同的,这样当改变其中一个对象的变量时,另一个对象的状态也将被改变。
除此之外,还可以通过修改__new__
方法来实现这种单例模式,而__new__
方法是用来创建对象实例的:
class Borg(object):
__shared_state = {}
def __new__(cls):
obj = super(Brog, cls).__new__(cls, *args, **kwargs)
obj.__dict__ = cls.__shared_state
return obj
元类级别的单例模式
元类是一个类的类,反过来说,一个类是它元类的实例。通过操作元类,可以创建自己类型的类。
Python中,一切皆对象。对于一个整数a=5
,查看a的类型type(a)
返回<type'int'>
,说明a是int类型,而type(int)
返回<type'type'>
,这意味着存在一个元类,因为int是type类型的类。
类的定义由其元类决定,当使用类A创建一个类时,Python通过A=type(name, bases,dict)
来创建:
- name:类的名称
- base:基类
- dict:属性变量
如果一个类有自定义的元类,例如Meta1
,则Python会通过A=Meta1(name,bases,dict)
来创建类。
举个元类的栗子:
class MyInt(type):
def __call__(cls, *args, **kwargs):
print("My int", args)
print("Do some thing")
return type.__call__(cls, *args, **kwargs)
class int(metaclass=MyInt):
def __init__(self, x, y):
self.x = x
self.y = y
i = int(4, 5)
# 输出结果为
# My int (4, 5)
# Do some thing
对于已经存在的类,创建新对象时,调用__call__
方法。当使用int(4, 5)实例化int类时,元类MyInt的__call__
被调用了,这意味着,元类控制着实例化操作。
由此可以想到,通过在元类中控制类的创建和对象实例化,实现单例模式(注意:为了控制类的创建和初始化,元类将覆盖__new__
和__init__
方法。)
简单实现一个单例模式:
class MetaSingleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Logger(metaclass=MetaSingleton):
pass
logger = Logger()
logger1 = Logger()
print(logger, logger1)