单例模式是常用的设计模式,在Python里有多种实现方式,这些实现方式灵活地利用了python的各种语言特点,深入研究一下,能帮你大大提升python的语言功力。
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
def test():
x = MyClass();
y = MyClass();
t = type(n)();
assert id(x) == id(y)
assert id(x) != id(t) && id(y) != id(t)
python的类变量相当于static变量,只存一份,所以可以利用它来实现单例。
class Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, BaseClass):
pass
分析:重载一个类的__new__方法能接管对象的创建过程。多个实例都会共享同一份_instance。
注意:Python的类变量并不是线程安全的。
metaclass是什么?其实相当于javascript中的prototype(原型)对象,作用就是你可以扩充一个已存在类的方法,如给标准类string加方法。
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
#Python2
class MyClass(BaseClass):
__metaclass__ = Singleton
#Python3
class MyClass(BaseClass, metaclass=Singleton):
pass
__call__该方法的功能类似于在类中重载 () 运算符,使得类实例对象可以像调用普通函数那样,以“对象名()”的形式使用。
def test_myclass():
obj1 = MyClass() ## 会调用__call__方法
obj2 = MyClass() ## 会再次调用__call__方法
assert id(obj1) == id(obj2)
def singleton(cls):
class class_w(cls):
_instance = None
def __new__(cls, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(cls, cls).__new__(cls, *args,**kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__name__ = class_.__name__
return class_w
@singleton
class MyClass(BaseClass):
pass
解释:创建每个对象时, new()被调用,_sealed第一次调用时由False变为True,后续调用不再执行super(class_w, self).init(*args, **kwargs)
class CoolClass():
def __init__(self, *args, **kwargs):
print('CoolClass is initialized.')
for k,v in kwargs.items():
print(f"__init__: {k} = {v}")
#
def __new__(cls, *args, **kwargs):
for k,v in kwargs.items():
print(f"__new__: {k} = {v}")
return super(CoolClass, cls).__new__(cls)
def __call__(cls, *args, **kwargs):
for k, v in kwargs.items():
print(f"__call__: {k} = {v}")
def test_object():
obj = CoolClass(username='haha', passwd='xixi')
obj(username='hoho', passwd='hihi')
结果是先调用__new__(),再调用__init__(),最后调用__call__()。
一个对象实现了__call__()方法,就变成了一个callable对象。有啥用处呢?就是在一些大型框架中,你可以先把这些callable对象创建好,然后在合适的时机调用它们,这给一些设计模式的实现带来了方便。还原一下就是下面的用法:
class CallableClass1:
def __call__(self, *args, **kwargs):
print('I am class1')
class CallableClass2:
def __call__(self, *args, **kwargs):
print('I am class2')
class CallableClass3:
def __call__(self, *args, **kwargs):
print('I am class3')
def test_callable():
objs = []
objs.append(CallableClass1())
objs.append(CallableClass2())
objs.append(CallableClass3())
for obj in objs:
if callable(obj):
obj()
实际场景中,CallableClass1~3有多种多样的构造方式,它们在初始化阶段创建好,然后暂时不用,需要的时候再用。