单例模式
单例模式:不管用类实例化对象多少次,所得到的对象都是同一个对象。这种模式的应用场景,如数据库连接,配置信息等。
1 通过类的嵌套实现单例
# create singleton by means of class nestification
class Singleton(object):
# really working class
class Wrapper_class(object):
def __init__(self, name):
self.name = name
def show_id(self):
return id(self)
def work(self):
print('i am working')
# save Wrapper_class instance
_instance = None
def __init__(self):
if Singleton._instance is None:
Singleton._instance = Singleton.Wrapper_class('wrapper')
# when get attribute if not exist, call this function. it return getattr function.
def __getattr__(self, item):
return getattr(self._instance, item)
# getattr include three params: instance name, attribute or method name, default value when instance not include attribute
if __name__ == '__main__':
a = Singleton()
b = Singleton()
print(a)
print(b)
print(a.show_id())
print(b.show_id())
以上代码修改自实验楼--python设计模式--单例。如有侵权请联系[email protected]
代码解析:Wrapper_class类是真正干活的类,它只进行一次实例化,并用Singleton类变量_instance保存,不管对Singleton类进行多少次实例化,内部由Wrapper_class类实例化出的干活的对象就只有一个。
Singleton类的方法__getattr__作用是:当调用了Singleton类不存在的方法或者属性时,就会运行Singleton的__getattr__方法。
return getattr(对象,属性或方法) 作用:检查属性或方法是否属于对象,属于的话,调用这个方法或者对象。
本例中,调用了Singleton类实例化对象的show_id()方法,但Singleton类中并未实现这个方法,因此首先调用了Singleton类的__getattr__方法,并返回了getattr(self._instance, item)方法,这个方法首先检查Wrapper_class类实例化的保存在_instance中的对象是否具有show_id()方法,正好Wrapper_class类中实现了这个方法,因此运行了这个方法,得到了结果
<__main__.Singleton object at 0x000002346197C358>
<__main__.Singleton object at 0x000002346197C550>
2423998891120
2423998891120
由结果知,不管实例化多少次Singleton类,但最终干活的对象都是同一个
2 装饰器实现单例
利用类装饰器实现单例
先上代码吧
# create singleton by means of class decorator
class Decorator(object):
def __init__(self, cls):
self._cls = cls
def __call__(self, *args, **kwargs):
try:
return self._instance
except AttributeError:
self._instance = self._cls()
return self._instance
@Decorator
class Work(object):
def __init__(self):
pass
def show_id(self):
return id(self)
if __name__ == '__main__':
a = Work()
b = Work()
print(a.show_id())
print(b.show_id())
结果为
1969722475520
1969722475520
上述代码中,类Decorator是装饰器类,其override了__call___方法,进行了custom。__call__方法使类Decorator实例化的对象可以像函数一样被调用。因此可以当做装饰器装饰其他函数或类。只有可调用对象才能作为装饰器
对于用函数去装饰函数这样的简单的装饰器类型,很容易理解其中代码的执行流程。但理解类装饰类这种类型确实让我头疼。就比葫芦画瓢地理解吧。函数装饰函数类型:装饰后返回的是装饰器内层的函数,然后替代原来的函数。那么同理,用类去装饰类,装饰后返回的应该是装饰器中的类的实例(别打脸,我猜的)。先就这样理解吧。正如上面的例子。类Work被类Decorator装饰,那么装饰后类Work就被传递进了Decorator的self._cls位置。然后把类Decorator的实例返回,并代替类Work的位置。当调用类Work进行实例化时,实际上调用的是装饰过以后的类Decorator的实例。仔细观察类Decorator的代码,可知,首次创建的时候,会生成一个实例属性self._instance。当第二次进行调用的时候,直接返回的是self._instance。因此就实现了单例模式。我对这段代码还是有很多疑惑。真正懂的大神可以评论告诉我啊,小弟在这里先谢过,有人说,这段代码不能用于多线程,我没试过,大家注意下
3 通过__new__方法实现单例
# crate singleton by means of __new__
class Singleton(object):
_instance = None # 一个下划线开头表示受保护的属性
# __new__函数在调用__init__方法前调用,目的是创建一个对象,因此,其方法的第一个参数要传递类名,cls,而不是self
# 只有创建了对象后才能使用self
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
if __name__ == '__main__':
a = Singleton()
b = Singleton()
print(id(a), id(b))
结果为
2025743751544 2025743751544