Python 中的单例模式

1.什么是单例模式
 
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。单例模式能控制一个类只能产生一个对象。
 
2.为什么需要单例模式
  • 当每个实例都会占用资源,而且实例初始化会影响性能,这个时候就可以考虑使用单例模式,它给我们带来的好处是只有一个实例占用资源,并且只需初始化一次;
  • 当有同步需要的时候,可以通过一个实例来进行同步控制,比如对某个共享文件(如日志文件)的控制,对计数器的同步控制等,这种情况下由于只有一个实例,所以不用担心同步问题。
 
3.单例模式应用场景
  • Python的logger就是一个单例模式,用以日志记录
  • Windows的资源管理器是一个单例模式
  • 线程池,数据库连接池等资源池一般也用单例模式
  • 网站计数器
4.在 Python 中,实现单例模式的四种方式
  • 使用模块
  • 使用装饰器(decorator)
  • 使用 __new__
  • 使用元类
4.1 使用模块
    Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
如果我们真的想要一个单例类,可以考虑这样做:
# mysingleton.py 
class My_Singleton(object): 
    def foo(self): 
        pass 
my_singleton = My_Singleton()

将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

from mysingleton import my_singleton
my_singleton.foo()
 
4.2 使用装饰器
    装饰器维护一个字典对象instances,缓存了所有单例类,只要单例不存在则创建,已经存在直接返回该实例对象。
我们定义一个装饰器 singleton,它返回了一个内部函数 wrapper,该函数会判断某个类是否在字典 instances 中,如果不存在,则会将 cls 作为 key,cls(*args, **kw) 作为 value 存到 instances 中,否则,直接返回 instances[cls]。
 
使用装饰器实现单例模式的代码如下:
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
 
4.3 使用__new__
 
__new__方法:  __new__()方法用于定义创建对象时执行的操作
object类中的__new__()方法完成对象创建过程中的内存空间申请,对象属性初始化等一系列的操作。__new__是真正创建实例对象时用到的方法,所以重写基类的__new__方法,以此来保证创建对象的时候只生成一个实例。
注意事项:    
1.__new__()方法创建对象时自动运行。     
2.覆盖object类中的__new__方法后创建对象    将执行覆盖后的方法。
注意事项:  
__new__()方法仅仅是python开放出来给用户干预创建对象时的一个操作入口,该方法并不是直接完成分配内存、创建对象的操作,创建对象的操作由python底层统一管理。
 
使用__new__方法实现单例模式的代码如下:
class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
        return cls._instance

class MyClass(Singleton):
    pass

foo1 = MyClass()
foo2 = MyClass()
print(foo1)
print(foo2)
 
4.4 使用元类
元类是用于创建类对象的类,类对象创建实例对象时一定会调用__call__方法,因此在调用__call__时候保证始终只创建一个实例即可,type是python中的一个元类。
元类(metaclass)可以控制类的创建过程,它主要做三件事:
  拦截类的创建
  修改类的定义
  返回修改后的类
 
使用元类实现单例模式的代码如下:
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(object):
#     __metaclass__ = Singleton

# Python3
class MyClass(metaclass=Singleton):
    pass

foo1 = MyClass()
foo2 = MyClass()
print(foo1)
print(foo2)

 

posted @ 2018-11-26 22:27 皮皮虾打怪兽 阅读(...) 评论(...) 编辑 收藏