Python 实现单例

Python 小记 2019-06-11 4007 字 961 浏览 点赞

起步

单例模式是一种常用的软件设计模式,用来确保一个类只会有一个实例存在。

以下是 Python 中实现单例模式的多种方法,环境基于 Python3.6.6。

__new__函数

class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

每次实例化一个对象时,都会先调用 __new__() 创建一个对象,再调用 __init__() 函数初始化数据。因而,在 new 函数中判断 Singleton类 是否已经实例化过,如果不是,调用父类的 new 函数创建实例;否则返回之前创建的实例。

_instance 作为类属性,保证了所有对象的 _instance 都是同一个。

元类 metaclass

class SingletonMetaClass(type):
    _instance = None

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = super().__call__(*args, **kwargs)
        return self._instance

class Singleton(metaclass=SingletonMetaClass):
    pass

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

当一个类设置了元类以后,创建对象是通过调用元类中的 __call__() 函数实现。这一点你可以通过对以下代码做断点运行来理解:

class SigletonMetaClass(type):
    _instance = None

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)  # 断点1

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = super().__call__(*args, **kwargs)
        return self._instance  # 断点2

class Singleton(metaclass=SigletonMetaClass):
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls)  # 断点3

因此,用元类实现单例时仍需按照三步骤:1. 拦截 2. 判断是否已经创建过对象 3. 返回对象。与上个方法相比,区别在于拦截的地点不同。

装饰器

用装饰器实现单例,思路与其他一致,改变的同样是拦截地点与记录位置。

函数装饰器

def SingletonDecorator(cls):
    _instance = None

    def get_instance(*args, **kwargs):
        nonlocal _instance
        if _instance is None:
            _instance = cls(*args, **kwargs)
        return _instance
    return get_instance

@SingletonDecorator
class Singleton(object):
    pass

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

类装饰器

class SingletonDecorator(object):
    _instance = None

    def __init__(self, cls):
        self._cls = cls

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = self._cls(*args, **kwargs)
        return self._instance

@SingletonDecorator
class Singleton(object):
    pass

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

方法

静态方法 staticmethod

class Singleton(object):
    _instance = None

    @staticmethod
    def get_instance():
        cls = __class__

        if cls._instance is None:
            cls._instance = super(cls, cls).__new__(cls)
        return cls._instance

# 示例:
a = Singleton.get_instance()
b = Singleton.get_instance()
# id(a) == id(b)

在静态函数中,既不会传入 cls 也不会有 self。为了在静态函数中使用 cls 的同时,避免硬编码,可使用内置变量 __class__。在一个类的作用域中,__class__ 等于类对象,即:__class__ == Singleton

类方法 classsmethod

class Singleton(object):
    _instance = None

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

# 示例:
a = Singleton.get_instance()
b = Singleton.get_instance()
# id(a) == id(b)

与静态函数类似。

名字覆盖

class Singleton(object):
    def __call__(self):
        return self

Singleton = Singleton()

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

实例名覆盖类名后,执行 Singleton() 就是在调用 __call__() 函数,总是返回自身。

属性共享

class Singleton(object):
    _state = {}

    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls)
        obj.__dict__ = cls._state
        return obj

    def __init__(self, name):
        self.name = name

# 示例:
a = Singleton()
b = Singleton()
# id(a) != id(b)

实例对象的私有属性存放在 __dict__ 中。因此,将所有对象指向同一个属性 Singleton._state,即便它们的 id值 不同,由于共享属性仍实现了单例效果。



本文由 Guan 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论