一、通过模块调用的方式实现
在python3中,首次导入模块文件时,会在程序目录下的__pycache__
目录下生成pyc
文件,再次导入时,将直接加载pyc
文件。
因此,只需要把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
二、使用__new__方法(饿汉式)
# 饿汉式
class HungrySingleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(HungrySingleton, "__instance"):
cls.__instance = super(HungrySingleton, cls).__new__(cls, *args, **kwargs)
return cls.__instance
既然有饿汉式,也会有懒汉式,懒汉式通过类方法来实现。
class LazySingleton(object):
@classmethod
def get_instance(cls):
if not hasattr(LazySingleton, "__instance"):
cls.__instance = LazySingleton()
return cls.__instance
但是懒汉式的实现是线程不安全的,多线程的情况下可能会获得不同的单例对象的情况。解决的办法就是加互斥锁,但是会降低效率。
import threading
def synchronized(func):
func.__lock__ = threading.Lock()
def lock_func(*args, **kwargs):
with func.__lock__:
return func(*args, **kwargs)
return lock_func
class LazySingleton(object):
@classmethod
@synchronized
def get_instance(cls):
if not hasattr(LazySingleton, "__instance"):
cls.__instance = LazySingleton()
return cls.__instance
三、使用装饰器
# wraps 装饰器修复,不会改变原函数信息
from functools import wraps
# singleton装饰器
def singleton(cls):
instances = {}
@wraps(cls)
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
四、使用元类
# 用元类的__call__方法来实现, 元类的__call__方法会在 以这个类为元类的类实例化的时候被调用
def SingletonMetaClass(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "__instance"):
cls.__instance = super().__call__(*args, **kwargs)
return cls.__instance
class A(metaclass=SingletonMetaClass):
pass