Python单例模式的实现

written on Tue 26 April 2016 by

由于实现的方式很多,先来3种。

1. 类实例实现的单例装饰器

import functools

class Singleton(object):

    def __init__(self):
        self.instances = {}

    def __call__(self, cls):
        @functools.wraps(cls)
        def wrapper(*args, **kwargs)
            if not self.instances.get(cls):
                self.instances[cls] = cls(*args, **kwargs)
            return self.instances[cls]
        return wrapper

singleton = Singleton()

# 用法
@singleton
class Test(object):
    pass

if __name__ == '__main__':
    t1 = Test()
    t2 = Test()
    print(t1, t2)
    print(type(t1), type(t2))
    assert t1 == t2

# 这种方式有一个缺点,就是Test这个类会变成一个function, 
# 这样的话就无法使用instance等方式了。

2. 类实现的单例装饰器

class Singleton(object):

    def __init__(self, cls):
        self.cls = cls
        self.cls_instance = None

    def __call__(self, *args, **kwargs):
        if not self.cls_instance:
            self.cls_instance = self.cls(*args, **kwargs)
        return self.cls_instance

@Singleton
class Test(object):
    pass


if __name__ == '__main__':
    print(Test)
    t1 = Test()
    t2 = Test()
    print(t1, t2)
    assert t1 == t2

# 这种方式Test其实已经是single的一个实例了
# 缺点和第一种方式一样,Test已经不是原来的Test了
# 而t1, t2却还是原来的Test的实例
# 对于这种方式我还存有疑虑,但是又说不出来
# 总感觉怪怪的

3. metaclass元类

class Singleton(type):
    _instances = {}
    def __cal__(self, *args, **kwargs):
        if self not in self._instances:
            self._instances[self] = super(Singleton, self).__call__(*args, *kwargs)
        return self._instances[self]

# py2写法
class Test(object):
    __metaclass__ = Singleton

    pass

# py3写法
class Test(object, metaclass=Singleton):
    pass

if __name__ == '__main__':
    print(Test)
    t1 = Test()
    t2 = Test()
    print(t1, t2)
    assert t1 == t2
    print(isinstance(t1, Test)

# 使用元类是最好的,因为Test的行为都没有被改变
# 所以isinstance, type等函数的调用都没有影响
# 不过理解起来可能会有一些困难了
# 因为我觉得自己理解的还有一些不够通透

This entry was tagged on #singleton and #装饰器

comments powered by Disqus
 

Tags