Python学习之——单例模式
参考
python之metaclass+singleton(一)
python之metaclass+singleton(二)
python之metaclass+singleton(三)
1 利用__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 = None
def __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__ = Singleton
foo1 = 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 Lock
class SingletonClass(object):
instance = None
lock = Lock()
def __new__(cls, *args, **kwargs):
if cls.instance:
return cls.instance
with cls.lock:
# double check
if 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 threading
def 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):
pass
foo1 = 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来实现单例了