Python单例模式的六种实现
什么叫做单例模式
单例模式是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在,第一次创建实例时是真正的创建了一个实例,而后面创建的实例则是第一次创建的实例的一个引用,是同一个实例。
单例模式多种实现
全局变量方式实现
class Singleton:
def __init__(self):
print('Creating.')
settings_instance = None
def Settings():
global settings_instance
if settings_instance is None:
settings_instance = Singleton()
return settings_instance
s = Settings()
s2 = Settings()
print(s is s2)
元类方式实现
class SingletonMetaclass(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super().__call__(*args, **kwargs)
return self.__instance
class Spam(metaclass=SingletonMetaclass):
def __init__(self):
print('Creating Spam')
s = Spam()
s2 = Spam()
print(s is s2)
通过元类方式,定义的元类里面定义两个方法__init__
、__call__
。__init__
初始化一个类(元类的一个实例),__call__
返回一个类(元类的一个实例),如果这个类已经存在,则直接返回,否则创建一个新的类。
装饰器方式实现
def singleton(cls):
instance = {}
def single(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return single
@singleton
class Settings:
def __init__(self):
print("init instance.")
s1 = Settings()
s2 = Settings()
print(id(s1))
print(id(s2))
print(s1 is s2)
装饰器方式实现是将一个类传递到一个函数里面进行创建,同时判断是否该类已经创建过实例,如果创建过实例,则直接返回创建的实例即可,否则创建新的实例并返回。
类方法方式实现
class Singleton:
instance = None
@classmethod
def singleton(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = cls(*args, **kwargs)
return cls.instance
s = Singleton.singleton()
s2 = Singleton.singleton()
print(id(s))
print(id(s2))
print(s is s2)
也可以使用静态方法创建,静态方法的缺点是一旦类名被改变,则静态方法里面的类名也得改变。
控制类构造函数方式实现
class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "cls_instance"):
cls.cls_instance = super().__new__(cls, *args, **kwargs)
return cls.cls_instance
class Settings(Singleton):
def do_things(self):
self.name = "yuziyue"
s = Settings()
s.do_things()
s2 = Settings()
print(s2.name)
print(s is s2)
这种方式实现有一个问题,就在在定义Settings
类时,不能写__init__
初始化函数,只能是创建实例后,通过实例方法来定义属性。
import 方式实现
# config.py
class Settings():
redis = "127.0.0.1"
def __init__():
print("creating.")
settings = Settings()
# app1.py
from config import settings
print(settings.redis)
# app2.py
from config import settings
print(settings.redis)
Python的模块导入就是一个单例模式,在其他地方导入已经创建好的实例,则该实例不会重新被创建,而是实例本身。