在Python中创建单例模式

18 浏览
0 Comments

在Python中创建单例模式

这个问题并不是讨论单例模式是否可取、是否是反模式或者任何宗教战争,而是讨论如何在 Python 中最符合 Python 风格地实现该模式。在这种情况下,“最符合 Python 风格”指的是遵循“最小惊讶原则”。

我有多个类需要成为单例(我的用例是记录器,但这不重要)。我不希望在几个类中添加杂项内容,而是可以简单地继承或装饰。

最佳方法:


方法一:装饰器

def singleton(class_):
    instances = {}
    def getinstance(*args, **kwargs):
        if class_ not in instances:
            instances[class_] = class_(*args, **kwargs)
        return instances[class_]
    return getinstance
@singleton
class MyClass(BaseClass):
    pass

优点

  • 装饰器的添加方式通常比多重继承更加直观。

缺点

  • 使用MyClass()创建的对象将是真正的单例对象,但MyClass本身是一个函数,而不是一个类,因此无法从中调用类方法。此外,对于

    x = MyClass();
    y = MyClass();
    t = type(n)();
    

那么x == y,但x != t && y != t


方法二:基类

class Singleton(object):
    _instance = None
    def __new__(class_, *args, **kwargs):
        if not isinstance(class_._instance, class_):
            class_._instance = object.__new__(class_, *args, **kwargs)
        return class_._instance
class MyClass(Singleton, BaseClass):
    pass

优点

  • 它是一个真正的类

缺点

  • 多重继承——呕!__new__在继承自第二个基类时可能会被覆盖?需要思考的东西比必要的还多。

方法三:元类

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(BaseClass):
    __metaclass__ = Singleton
#Python3
class MyClass(BaseClass, metaclass=Singleton):
    pass

优点

  • 它是一个真正的类
  • 自动处理继承
  • 使用__metaclass__来达到其适当的目的(并使我意识到它)

缺点

  • 这里还有其他方法吗?

方法4:返回具有相同名称的类的装饰器

def singleton(class_):
    class class_w(class_):
        _instance = None
        def __new__(class_, *args, **kwargs):
            if class_w._instance is None:
                class_w._instance = super(class_w,
                                    class_).__new__(class_,
                                                    *args,
                                                    **kwargs)
                class_w._instance._sealed = False
            return class_w._instance
        def __init__(self, *args, **kwargs):
            if self._sealed:
                return
            super(class_w, self).__init__(*args, **kwargs)
            self._sealed = True
    class_w.__name__ = class_.__name__
    return class_w
@singleton
class MyClass(BaseClass):
    pass

优点

  • 它是一个真正的类
  • 自动覆盖继承

缺点

  • 每创建一个新类是否都有额外的开销?对于每个我们想要变成单例的类,这里我们都要创建两个类。虽然在我这个案例中这样做是没问题的,但我担心这种方式可能无法扩展。当然,人们也可以争论这种模式是否应该太容易扩展...
  • _sealed 属性有何意义
  • 无法使用 super() 调用基类上同名的方法,因为它们会递归。这意味着您无法自定义 __new__,也无法派生出需要您调用到 __init__ 的类。

方法5:一个模块

一个名为 singleton.py 的模块文件

优点

  • 简单胜于复杂

缺点

  • 不支持延迟实例化
admin 更改状态以发布 2023年5月22日
0
0 Comments

class Foo(object):
     pass
some_global_variable = Foo()

模块只会被导入一次,其他的都是过度思考。不要使用单例模式,尽量不要使用全局变量。

0