Python单例模式实现

Python单例模式实现

  单例模式是一种常用的软件设计模式,该模式的主要问题是确保某一个类只有一个实例存在。有时候再项目中难免需要一些全局唯一的对象,这些对象大多是一些工具性的东西,在python中实现单例模式大概有如下几种方法:
-类装饰器
-使用元类或者__call__
-使用__new__
-使用模块

1、使用类装饰器

使用装饰器实现单例类的时候,类本身并不知道自己是单例的,所以写代码的人可以不关心这个,只要正常写自己的类的实现就可以了,类的单例有装饰器保证。

def singleton(cls):
    instances = {}
    def _wrapper(*args,**kwargs):
        if cls not in instances:
            instances[cls] = cls(*args,**kwargs)
            return instances[cls]
    return _wrapper

你会发现singleton装饰器内部使用了一个dict,当然你也可以用其他的方式,不过一下的实现是错误的:

def singleton(cls):
    _instance = None #外部作用域的引用对于嵌套的内部作用域是只读的
    def _wrapper(*args,**kwargs):
        if _instance is None:#解释器会抛出"UnboundLocalError: ...referenced before assignment"
            _instance = cls(*args,**kwargs)#赋值幸会将使解释器将"_instance"看做局部变量
        return _instance
    return _wrapper


2、使用元类(__metaclass__)和可调用对象(__call__)

  python的对象系统中一切皆对象,可以称之为”类型对象”,比较绕,但是仔细想想也不难。类本身也是一种对象,只不过这种对象很特殊,它表示某一种类型。是对象,那必然是实例化来的,那么谁实例化后是这种类型对象呢?答案就是元类。
  python中,class关键字表示定义一个类对象,此时解释器会按照一定的规则寻找__metaclass__,如果找到了, 就调用对应的元类来实例化该类对象。如果没有找到,就会调用type元类来实例化该对象。
  __call__是python的魔法方法,Python的面向对象是”Duck Type”的,意味着对象的行为可以通过实现协议来实现,可以看作是一种特殊的接口形式。某个类实现了__call__方法意味着该类的对象是可调用的。可以像函数调用那样。再考虑一下foo = Foo()这种实例化的形式,是不是很像。结合元类的概念,可以看出,Foo类是单例的,则在调用Foo()的时候每次都返回了同样的对象。而Foo作为一个类对象是单例的,意味着它的类(即生成它的元类)是实现了__call__方法的。所以可以如下实现:

class SingleTon(type):
    def __init__(cls,name,bases,attrs):
        super(SingleTon,cls).__init__(name,bases,attrs)
        cls._instance = None
    def __call__(cls,*args,**kwargs):
        if cls._instance is None:
        #以下不要使用"cls._instance(*args,**kwargs)",防止死循环,cls的调用行为已经被当前的'__call__'协议拦截了,使用super(SingleTon,cls).__call__来生成cls的实例。
            cls._instance = super(SingleTon,cls).__call__(*args,**kwargs)
    return cls._instance

class Foo(object):#单例类
    \__metaclass__ = SingleTon

测试:

>>>a = Foo()
>>>b = Foo()
>>>a is b
>>>True
>>>a.x = 1
>>>b.x
>>>1


3、使用__new__

  __init__不是Python对象的构造方法,__init__只负责初始化实例对象,在调用__init__方法之前,会首先调用__new__方法生成对象,可以认为__new__方法充当了构造函数的角色。所以可以在__new__中加以控制,使得某个类只能生成唯一对象。具体实现时可以实现一个父类,重载__new__方法,单例类只需要继承这个父类就好。

class SingleTon(object):
    def __new__(cls,*args,**kwargs):
        if not hasattr(cls,'_instance'):
            cls._instance = super(SingleTon,cls).__new__(*args,**kwargs)
        return cls._instance

class Foo(SingleTon):#单例类
    pass    



4、与实现3类似,采用单独的类

class Foo(object):
    _instance = None
    def __new__(cls,*args,**kwargs):
    #实现__new__方法,_instance表示该类的实例,在生成对象实例的时候先判断是否已经生成了该对象,如果没有则生成该对象实例,有则返回该实例对象。
        if _instance is None:
            _instance = super(Foo,cls).__new__(cls,*args,**kwargs)
        return _instance


使用模块
其实python的模块就是天然的单例,因为模块在第一次导入时,会生成.pyc文件,当第二次导入时,就会直接加载.pyc,而不会再次执行模块代码。因此,我们只需要把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的需要一个单例类,可以考虑这样做:

#mysingleton.py
class MySingleTon(object):
    def foo(self):
        pass

my_singleton = MysingleTon()    

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

from mysingleton import my_singleton
my_singleton.foo()


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章