Python学习之——单例模式
- 参考
- 1 利用__metaclass__实现单例
- super的用法
- class Singleton(type)元类
- 2 重载__new__方法实现单例模式
- 3 利用装饰器实现单例
- 考虑一个类如果继承一个单例类的问题
参考
python之metaclass+singleton(一)
python之metaclass+singleton(二)
python之metaclass+singleton(三)
1 利用__metaclass__实现单例
揭开Python元类(metaclass)神秘的面纱
super的用法
【python】B站最细致的super()详解,一定有你不知道的知识!
super(arg1):
一个参数:
# 返回一个未bind的对象
ubo = super(Male)
# bind一个object
ubo.__get__(self).__init__(age, name)super(arg1,arg2):
两个参数:
arg1:决定从MRO链中的arg1后开始
arg2:决定使用该super函数的对象object和对象的MRO,注意arg2也可以是class,但不常用
class Singleton(type)元类
singleton文件夹
__ init__.py文件
# -*- coding: utf-8 -*-
"""单例."""class Singleton(type):def __init__(cls, name, bases, dict):super(Singleton, cls).__init__(name, bases, dict)cls.instance = Nonedef __call__(cls, *args, **kwargs):print 'call Singleton __call__'if cls.instance is None:# 等价于cls.instance = type.__call__(cls, *args, **kwargs)cls.instance = super(Singleton, cls).__call__(*args, **kwargs)return cls.instance
利用__metaclass__实现单例的示例
class Foo(object):__metaclass__ = Singletonfoo1 = Foo()
foo2 = Foo()
#运行结果应该为True, 但实际是False, 想想为啥会出现这样的异常??
print foo1 is foo2
请思考如下问题:
-
不用Foo类去创建实例,仅仅只有Foo和Singleton定义,执行脚本,会不会像第二节中打印出print语句?
不会 -
__call__在哪里调用?
还记得__call__是怎么调用的吗?是一个类实例化出来的对象obj,直接通过obj ()形式调用了 __ call __。
此处的元类根本没有复写 __new __和 __init __方法,Foo类就是Singleton创建出来的一个普通的类(就是一个Singleton类的对象,实例),因此Foo()会调用Singleton的 __call __。
__call__中限定了只能新建一个Foo类的对象。如果想要定义的类是单例的,只要定义类时指定__metaclass__ = Singleton即可。 -
继承Foo类的也会是单例吗?
class FooChild(Foo):def __init__(self, a):super(FooChild, self).__init__()
foo11 = FooChild()
foo22 = FooChild()
print foo11 is foo22 #运行结果为True
2 重载__new__方法实现单例模式
“双重检查锁定”(Double-Checked Locking)单例模式
from threading import Lockclass SingletonClass(object):instance = Nonelock = Lock()def __new__(cls, *args, **kwargs):if cls.instance:return cls.instancewith cls.lock:# double checkif not cls.instance:cls.instance = super(SingletonClass, cls).__new__(cls, *args, **kwargs)return cls.instance# 测试
if __name__ == "__main__":s1 = SingletonClass()s2 = SingletonClass()print(s1 is s2) # 应该输出 True# 在多线程环境中测试import threadingdef test_singleton():instance = SingletonClass()print(f"Instance id in thread {threading.current_thread().name}: {id(instance)}")threads = [threading.Thread(target=test_singleton) for _ in range(5)]for t in threads:t.start()for t in threads:t.join()
3 利用装饰器实现单例
def singleton(cls):instances = {}def wrapper(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return wrapper@singleton
class Foo(object):passfoo1 = Foo()#等同于
#class Foo(object):
# pass
#foo1 = singleton(Foo)
foo2 = Foo()
print foo1 is foo2 #运行结果为True
考虑一个类如果继承一个单例类的问题
3 中继承会出现问题
# 报错function() argument 'code' must be code, not str
# 因为Foo被装饰后成为了函数而不是class
# class FooChild(Foo):# 改成如下
ClassFoo = Foo().__class__class FooChild(ClassFoo):def __init__(self, a=0):super(FooChild, self).__init__()
但是这里的 FooChild就不在是单例了,也没法在加上@singleton来实现单例了