在Python中创建单例模式
在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日