在Python中创建单例

北战南征 提交于 2020-12-17 15:28:29

问题:

This question is not for the discussion of whether or not the singleton design pattern is desirable, is an anti-pattern, or for any religious wars, but to discuss how this pattern is best implemented in Python in such a way that is most pythonic. 这个问题不是为了讨论是否需要单例设计模式 ,是否是反模式,还是针对任何宗教战争,而是要讨论如何以最pythonic的方式在Python中最好地实现此模式。 In this instance I define 'most pythonic' to mean that it follows the 'principle of least astonishment' . 在这种情况下,我定义“最pythonic”来表示它遵循“最少惊讶的原理”

I have multiple classes which would become singletons (my use-case is for a logger, but this is not important). 我有多个将成为单例的类(我的用例用于记录器,但这并不重要)。 I do not wish to clutter several classes with added gumph when I can simply inherit or decorate. 当我可以简单地继承或修饰时,我不希望增加gumph来使几个类杂乱无章。

Best methods: 最佳方法:


Method 1: A decorator 方法1:装饰器

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

Pros 优点

  • Decorators are additive in a way that is often more intuitive than multiple inheritance. 装饰器的添加方式通常比多重继承更直观。

Cons 缺点

  • While objects created using MyClass() would be true singleton objects, MyClass itself is aa function, not a class, so you cannot call class methods from it. 使用MyClass()创建的对象将是真正的单例对象,而MyClass本身是一个函数,而不是类,因此您不能从中调用类方法。 Also for m = MyClass(); n = MyClass(); o = type(n)(); 同样对于m = MyClass(); n = MyClass(); o = type(n)(); m = MyClass(); n = MyClass(); o = type(n)(); then m == n && m != o && n != o 然后m == n && m != o && n != o

Method 2: A base class 方法2:一个基类

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

Pros 优点

  • It's a true class 这是一个真正的课堂

Cons 缺点

  • Multiple inheritance - eugh! 多重继承-好! __new__ could be overwritten during inheritance from a second base class? __new__是否可以在从第二个基类继承时被覆盖? One has to think more than is necessary. 人们必须思考的超出了必要。

Method 3: A metaclass 方法3: 元类

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

Pros 优点

  • It's a true class 这是一个真正的课堂
  • Auto-magically covers inheritance 自动神奇地涵盖继承
  • Uses __metaclass__ for its proper purpose (and made me aware of it) __metaclass__用于其适当的目的(并使我意识到这一点)

Cons 缺点

  • Are there any? 有吗

Method 4: decorator returning a class with the same name 方法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

Pros 优点

  • It's a true class 这是一个真正的课堂
  • Auto-magically covers inheritance 自动神奇地涵盖继承

Cons 缺点

  • Is there not an overhead for creating each new class? 创建每个新类没有开销吗? Here we are creating two classes for each class we wish to make a singleton. 在这里,我们为希望创建单例的每个类创建两个类。 While this is fine in my case, I worry that this might not scale. 虽然这对我来说很好,但我担心这可能无法扩展。 Of course there is a matter of debate as to whether it aught to be too easy to scale this pattern... 当然,要扩展这种模式是否太容易了还有争议。
  • What is the point of the _sealed attribute _sealed属性的意义是什么
  • Can't call methods of the same name on base classes using super() because they will recurse. 无法使用super()在基类上调用相同名称的方法,因为它们会递归。 This means you can't customize __new__ and can't subclass a class that needs you to call up to __init__ . 这意味着您不能自定义__new__ ,也不能将需要调用__init__类作为子类。

Method 5: a module 方法5:一个模块

a module file singleton.py 一个模块文件singleton.py

Pros 优点

  • Simple is better than complex 简单胜于复杂

Cons 缺点


解决方案:

参考一: https://stackoom.com/question/SMlJ/在Python中创建单例
参考二: https://oldbug.net/q/SMlJ/Creating-a-singleton-in-Python
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!