前言
相信每一个人都渴望有一个纯洁的爱情,希望找到唯一的她。不管你是单身狗一个,还是已经成双成对,肯定都希望你的伴侣是唯一的!程序如人生,程序也一样,有一些类你希望它只有一个实例。
我们用程序来模拟一个真爱。
实战
「源码示例」
class MyBeautifulGril(object):
"""我的漂亮女神"""
__instance = None
__isFirstInit = False
def __new__(cls, name):
if not cls.__instance:
MyBeautifulGril.__instance = super().__new__(cls)
return cls.__instance
def __init__(self, name):
if not self.__isFirstInit:
self.__name = name
print("遇见" + name + ",我一见钟情!")
MyBeautifulGril.__isFirstInit = True
else:
print("遇见" + name + ",我置若罔闻!")
def showMyHeart(self):
print(self.__name + "就我心中的唯一!")
「测试代码」
def TestLove():
jenny = MyBeautifulGril("Jenny")
jenny.showMyHeart()
kimi = MyBeautifulGril("Kimi")
kimi.showMyHeart()
print("id(jenny):", id(jenny), " id(kimi):", id(kimi))
「输出结果」
遇见Jenny,我一见钟情!
Jenny就我心中的唯一!
遇见Kimi,我置若罔闻!
Jenny就我心中的唯一!
id(jenny): 47127888 id(kimi): 47127888
看到了没,一旦你初次选定了 Jenny,不管换几个女人,你心中念叨的还是 Jenny!这才是真爱啊!哈哈……
从剧情中思考单例模式 单例模式
❝Ensure a class has only one instance, and provide a global point of access to it. 确保一个类只有一个实例,并且提供一个访问它的全局方法
❞
设计思想 有一些人,你希望是唯一的,程序也一样,有一些类,你希望实例是唯一的。单例就是一个类只能有一个对象(实例),单例就是用来控制某些事物只允许有一个个体,比如在我们生活的世界中,有生命的星球只有一个——地球(至少到目前为止人类所发现的世界中是这样的)。
人如果脚踏两只船,你的生活将会翻船!程序中的部分关键类如果有多个实例,将容易使逻辑混乱,程序崩溃!
单例模式的模型抽象 代码框架 单例的实现方式有很多种,下面列出几种常见的方式。
重写 new 和 init 方法
「源码示例」
class Singleton1(object):
"""单例实现方式一"""
__instance = None
__isFirstInit = False
def __new__(cls, name):
if not cls.__instance:
Singleton1.__instance = super().__new__(cls)
return cls.__instance
def __init__(self, name):
if not self.__isFirstInit:
self.__name = name
Singleton1.__isFirstInit = True
def getName(self):
return self.__name
# Test
tony = Singleton1("Tony")
karry = Singleton1("Karry")
print(tony.getName(), karry.getName())
print("id(tony):", id(tony), "id(karry):", id(karry))
print("tony == karry:", tony == karry)
输出结果
Tony Tony
id(tony): 46050320 id(karry): 46050320
tony == karry: True
在 Python 3 的类中,new 负责对象的创建,而 init 负责对象的初始化;new 是一个类方法,而 init 是一个对象方法。
new 是我们通过类名进行实例化对象时自动调用的,init 是在每一次实例化对象之后调用的,new 方法创建一个实例之后返回这个实例对象,并将其传递给 init 方法的 self 参数。
在上面的示例代码中,我们定义了一个静态的 instance 类变量,用来存放 Singleton1 的对象,new 方法每次返回同一个_instance对象_(若未初始化,则进行初始化)。因为每一次通过 s = Singleton1() 的方式创建对象时,都会自动调用 init 方法来初始化实例对象;因此 isFirstInit 的作用就是确保只对 instance 对象进行一次初始化,故事剧情中的代码就是用这种方式实现的单例。
在 Java 和 C++ 这种静态语言中,实现单例模式的一个最简单的方法就是:将构造函数声明成 private,再定义一个 getInstance() 的静态方法返回一个对象,并确保 getInstance() 每次返回同一个对象即可,如下面的 Java 示例代码。
/**
* Java中单例模式的实现,未考虑线程安全
*/
public class Singleton {
private static Singleton instance = null;
private String name;
private Singleton(String name) {
this.name = name;
}
public static Singleton getInstance(String name) {
if (instance == null) {
instance = new Singleton(name);
}
return instance;
}
}
Python 中 new 和 init 都是 public 的,所以我们需要通过重写 new 和 init 方法来改造对象的创建过来,从而实现单例模式。如果你要更详细地了解 Python 中 new 和 init 的原理和用法,请参见《深入理解 Python 中的 new 和 init》
自定义 metaclass 的方法
「源码实例」
class Singleton2(type):
"""单例实现方式二"""
def __init__(cls, what, bases=None, dict=None):
super().__init__(what, bases, dict)
cls._instance = None # 初始化全局变量cls._instance为None
def __call__(cls, *args, **kwargs):
# 控制对象的创建过程,如果cls._instance为None则创建,否则直接返回
if cls._instance is None:
cls._instance = super().__call__(*args, **kwargs)
return cls._instance
class CustomClass(metaclass=Singleton2):
"""用户自定义的类"""
def __init__(self, name):
self.__name = name
def getName(self):
return self.__name
tony = CustomClass("Tony")
karry = CustomClass("Karry")
print(tony.getName(), karry.getName())
print("id(tony):", id(tony), "id(karry):", id(karry))
print("tony == karry:", tony == karry)
「输出结果」
Tony Tony
id(tony): 50794608 id(karry): 50794608
tony == karry: True
在上面的代码中,我们定义了一个 metaclass(Singleton2)来控制对象的实例化过程。在定义自己的类时,我们通过 class CustomClass(metaclass=Singleton2) 来显示地指定 metaclass 为 Singleton2。如果你还不太熟悉 metaclass,想了解更多关于它的原理,请参见《附录 Python 中 metaclass 的原理》
装饰器的方法
「源码实例」
def singletonDecorator(cls, *args, **kwargs):
"""定义一个单例装饰器"""
instance = {}
def wrapperSingleton(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return wrapperSingleton
@singletonDecorator
class Singleton3:
"""使用单例装饰器修饰一个类"""
def __init__(self, name):
self.__name = name
def getName(self):
return self.__name
tony = Singleton3("Tony")
karry = Singleton3("Karry")
print(tony.getName(), karry.getName())
print("id(tony):", id(tony), "id(karry):", id(karry))
print("tony == karry:", tony == karry)
「输出结果」
Tony Tony
id(tony): 46206704 id(karry): 46206704
tony == karry: True
装饰器的实质就是对传进来的参数进行补充,可以在原有的类不做任何代码变动的前提下增加额外的功能,使用装饰器可以装饰多个类。用装饰器的方式来实现单例模式,通用性非常好,在实际项目中用的非常多。
上面的代码框架可用类图表示如下

基于框架的实现 通过上面的方式三,我们知道,定义通用的装饰器方法之后再用它去修饰一个类,这个类就成了一个单例类,使用起来非常方便。最开始的示例代码我们假设它为 version 1.0,那么再看看基于装饰器的 version 2.0 吧
@singletonDecorator
class MyBeautifulGril(object):
"""我的漂亮女神"""
def __init__(self, name):
self.__name = name
if self.__name == name:
print("遇见" + name + ",我一见钟情!")
else:
print("遇见" + name + ",我置若罔闻!")
def showMyHeart(self):
print(self.__name + "就我心中的唯一!")
「输出结果」
遇见Jenny,我一见钟情!
Jenny就我心中的唯一!
Jenny就我心中的唯一!
id(jenny): 58920752 id(kimi): 58920752