使用单例模式的好处:python
在python3中,首次导入模块文件时,会在程序目录下的__pycache__目录中生成pyc文件,再导入时,将直接加载pyc文件。所以,只需把相关的函数和数据定义在一个模块中,就能够得到一个单例对象了。设计模式
class singleton_cal: def foo(self) pass export_singleton = singleton_cal()
from singleton_demo import export_singleton a = export_singleton b = export_singleton print(id(a) == id(b))
当实例化一个对象时,先调用__new__方法(未定义时调用object.__new__)实例化对象,而后调用__init__方法进行对象初始化。安全
因此,能够声明一个私有类变量__instance。当__instance不为None时,表示系统中已有实例,直接返回该实例;若__instance为None时,表示系统中尚未该类的实例,则建立新实例并返回。多线程
class Singleton(object): __instance = None
def __new__(cls, *args, **kwargs): if not cls.__instance: cls.__instance = super().__new__(cls, *args, **kwargs) return cls.__instance a = Singleton() b = Singleton() print(id(a) == id(b))
from functools import wraps 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 @singleton class Singleton(object): def foo(self): pass a = Singleton() b = Singleton() print(id(a) == id(b))
只有第一次调用Singleton类时,装饰器才会从instances={}开始执行,之后再调用该类时,都只执行get_instance函数,这是装饰器的特性。并发
利用装饰器的这个特性,能够实现单例模式。复用装饰器,可使多个类实现单例模式。函数
元类建立了全部的类型对象(包括object对象),系统默认的元类是type。性能
执行顺序:先定义metaclass,而后在类定义时,经过metaclass建立类,最后经过定义好的类建立实例。spa
因此,metaclass容许你建立类或者修改类。换句话说,能够把类当作是metaclass建立出来的“实例”。线程
元类中定义的__new__方法,在以该类为元类的类定义时自动调用。例如:类A以类B为元类,当定义类A时,类B的__new__方法将会被自动调用。设计
元类中定义的__call__方法,在以该类为元类的类建立实例时自动调用。例如:类A以类B为元类,当类A建立实例时,类B的__call__方法将会被自动调用。
自定义元类时,一般继承自type。
class MetaClass(type): def __init__(cls, *args, **kwargs):
# cls 代指以该类为元类的类 Foo super(MetaClass, cls).__init__(*args, **kwargs)
def __new__(mcs, *args, **kwargs):
# mcs 代指元类自身
print("MetaClass.__new__: ", mcs)
return super().__new__(mcs, *args, **kwargs) def __call__(cls, *args, **kwargs):
# cls 代指以该类为元类的类 Foo print("CLS: ", cls) obj = cls.__new__(cls, *args, **kwargs) cls.__init__(obj, *args, **kwargs) return obj class Foo(metaclass=MetaClass):
# 定义类Foo时,将调用元类的__new__方法和__init__方法。就跟通常普通类实例化时调用__new__方法和__init__方法同样。 def __init__(self, name): self.name = name
# Foo 实例化时会调用元类的__call__方法。 a = Foo("ABC")
声明一个私有变量__instance保存类实例。__instance为None时,调用type的__call__方法为类建立实例。
class SingletonMeta(type): __instance = None def __call__(cls, *args, **kwargs): if not cls.__instance: cls.__instance = type.__call__(cls, *args, **kwargs) return cls.__instance class MyClass(metaclass=SingletonMeta): def foo(self): pass a = MyClass() b = MyClass() print(id(a) == id(b))
class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
经过以上方法定义的单例模式,没法支持多线程。解决这个问题的办法是:加锁!未加锁部分并发执行,加锁部分串行执行。
import threading class Singleton(object): _instance_lock = threading.Lock() @classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task(arg): obj = Singleton.instance() print("Task {}".format(arg), id(obj)) for i in range(10): t = threading.Thread(target=task, args=[i,]) t.start()
使用类实现的单例模式,在使用时必须经过Singleton.instance()进行实例化。若是使用Singleton()进行实例化获得的不是单例。