1 __new__魔法方法
class Foo():
__instance = None
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance
v1 = Foo('www')
v2 = Foo('yyy')
print(v1 is v2)
2 元类__call__魔法方法
原理:类定义时会调用元类下的__init__(),类调用(实例化对象)时会调用元类下的__call__()
类定义时,给类新增一个空的属性,
第一次实例化时,实例化之后就将这个对象赋值给类的属性;
第二次再实例化时,直接返回类的这个数据属性
class MyType(type):
def __init__(self, *args, **kwargs):
# 类定义时调用此函数
super().__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
# 类实例化时调用此函数
if not self.__instance:
self.__instance = object.__new__(self)
self.__init__(self.__instance, *args, **kwargs)
return self.__instance
class Foo(metaclass=MyType):
def __init__(self, name):
self.name = name
v1 = Foo('www')
v2 = Foo('yyy')
print(v1 is v2)
3 函数装饰器
def outter(cls):
instance_dict = {} # cls: instance
def inner(*args, **kwargs):
if cls not in instance_dict:
instance_dict[cls] = cls(*args, **kwargs)
return instance_dict[cls]
return inner
@outter
class Foo():
def __init__(self, name):
self.name = name
v1 = Foo('www')
v2 = Foo('yyy')
print(v1 is v2)
4 总结 与 完善
上面三种方法均可实现单例模式, 但在高并发时, 多线程同时实例化一个对象, 还是可能会导致有多个实例的存在
一种简单的解决方案是采用互斥锁, 这里以方法一为例完善单例模式的实现
from threading import Lock
lock = Lock()
class Foo():
__instance = None
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
with lock:
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance
v1 = Foo('www')
v2 = Foo('yyy')
print(v1 is v2)