python——单例
一、单例模式的介绍
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
场景:
比如,我们用的 Django程序中的settings配置文件,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
在 Python 中,我们可以用多种方法来实现单例模式:
- 使用模块
- 使用 __ new __
- 使用装饰器(decorator)
- 使用元类(metaclass)
基于__new__方法实现
class One(object):
_instance = None
def __new__(cls, *args, **kw):
if not cls._instance:
cls._instance = object.__new__(cls, *args, **kw)
return cls._instance
s1=One()
s2=One()
#One类实例化出来的所有对象都是相同的对象
基于模块导入的方式实现 也是最常用的
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,模块中的代码会执行,同时会生成一个 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
实现单例模式,三个例子:
- 例一:
//one.py文件
class Person:
def walk(self,x):
print(f'向前走{x}米')
wangfei = Person()
//two.py文件
#第一次导入
from one import wangfei
print(id(wangfei.walk(100)))
#第二次导入
from one import wangfei
print(id(wangfei.walk(1000)))
#输出
向前走100米
1721431248
向前走1000米
1721431248
验证了这句:模块中的代码会执行,同时会生成一个 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
- 例二:
//three.py文件
class Person:
def walk(self,x):
print(f'向前走{x}米')
wangfei = Person()
//four.py
from three import wangfei,Person
print(id(wangfei))
print(id(Person()))
print(id(Person()))
#输出
1880091761016
1880091620408
1880089942224
导入模块中实例化的对象和导入模块中的类,再通过类实例化得到的对象都是不同的对象。
- 例三:
//one.py文件
class Person:
def walk(self,x):
print(f'向前走{x}米')
wangfei = Person()
//two.py
from one import wangfei
def func():
print(id(wangfei))
//three.py
from one import wangfei
from two import func
print(id(wangfei))
func()
#输出
2829704809720
2829704809720
在一个程序中,即便是在不同的py文件中导入同一个对象,它们其实也是同一个对象,第二次导入同样是直接加载第一次导入生成的 .pyc 文件。
补充:
单例模式 实现:
- 类方法
- 装饰器
- 基于模块 同上
- 基于元类
一个类只允许产生一个实例对象
# classmethod 类方法 执行时会把类当作参数传入
class Mysql:
_instance = None
def __init__(self,host,port):
self.host = host
self.port = port
@classmethod
def singleton(cls):
if not cls._instance:
cls._instance = cls('127.0.0.1',3306)
return cls._instance
print(id(Mysql.singleton()))
print(id(Mysql.singleton()))
#输出 2167369923160 2167369923160
装饰器
from functools import wraps
def singleton(cls):
cls._instance = cls('127.0.0.1',3306)
@wraps(cls)
def inner(*args,**kwargs):
if args or kwargs: #如果自己有参数就用自己的
obj = cls(*args,**kwargs)
return obj
return cls._instance
return inner
@singleton # Mysql = singleton(Mysql)
class Mysql:
def __init__(self,host,port):
self.host = host
self.port = port
obj1 = Mysql()
obj2 = Mysql()
obj3 = Mysql('12342',243)
print(id(obj1),id(obj2),id(obj3))
1872210011640 1872210011640 1872210011696
基于元类
class MymetaClass(type): #写个基类,基类必须继承type类
def __call__(self, *args, **kwargs):
if not getattr(self,'_instance'): #通过反射确认子类没有 _instance
self._instance = super().__call__(*args,**kwargs) #为子类设置_instance方法
return self._instance
class Mysql(metaclass=MymetaClass):
_instance = None
def __init__(self,host,port):
self.host = host
self.port = port
print(id(Mysql('127.9.0.1',9090)))
print(id(Mysql('127.9.0.2',9090)))
#输出
1190368475736 1190368475736