This question is not for the discussion of whether or not the 100 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. In this instance I define 'most pythonic' to mean that it follows the 'principle of least astonishment'.
我有多个类,它们将成为单例(我的用例是针对记录器的,但这并不重要).当我可以简单地继承或装饰时,我不希望用添加的gumph来扰乱几个类.
最佳方法:
方法一:装饰师
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
方法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
专业人士
- 这是一门真正的课
缺点
- 多重继承-呃!
__new__
可以在从第二个基类继承的过程中被覆盖?人们必须想得更多,而不是必要的.
Method 3: A metaclass
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:decorator返回同名的类
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
专业人士
- 这是一门真正的课
- 自动神奇地覆盖了继承
缺点
- 创建每一个新类都没有开销吗?这里我们 for each 类创建两个类,我们希望创建一个单例.虽然这在我的情况下很好,但我担心这可能无法扩展.当然,对于这种模式是否太容易扩展,存在争议...
-
_sealed
属性的意义是什么 - 不能使用
super()
在基类上调用同名方法,因为它们将递归.这意味着您不能自定义__new__
,也不能子类化需要您调用高达__init__
的类.
方法5:一个模块
模块文件singleton.py
专业人士
- 简单总比复杂好
缺点
- 不是懒洋洋地说