首页 文章

在Python中创建单例

提问于
浏览
637

这个问题不是讨论singleton design pattern是否可取,是反模式,还是任何宗教战争,而是讨论如何以最pythonic的方式在Python中最好地实现这种模式 . 在这个例子中,我定义'most pythonic'意味着它遵循'principle of least astonishment' .

我有多个类可以成为单例(我的用例是 Logger ,但这并不重要) . 当我可以简单地继承或装饰时,我不希望在添加gumph的几个类中混乱 .

最好的方法:


方法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

优点

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

缺点

  • 虽然使用MyClass()创建的对象将是真正的单例对象,但MyClass本身是一个函数,而不是类,因此您无法从中调用类方法 . 也适用于 m = MyClass(); n = MyClass(); o = type(n)(); 然后 m == n && m != o && n != o

方法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

优点

  • 这是一个真正的课程

缺点

  • 多重继承 - eugh!在从第二个基类继承期间,是否可以覆盖 __new__ ?人们必须思考的不仅仅是必要的 .

方法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

优点

  • 这是一个真正的课程

  • 自动神奇地涵盖了继承

  • 使用 __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__ 的类 .

19 回答

  • 0

    这是我实现单身人士的首选方式:

    class Test(object):
        obj = None
    
        def __init__(self):
            if Test.obj is not None:
                raise Exception('A Test Singleton instance already exists')
            # Initialization code here
    
        @classmethod
        def get_instance(cls):
            if cls.obj is None:
                cls.obj = Test()
            return cls.obj
    
        @classmethod
        def custom_method(cls):
            obj = cls.get_instance()
            # Custom Code here
    
  • -2

    这是我自己实现的单身人士 . 你所要做的就是装饰课程;要获得单例,您必须使用 Instance 方法 . 这是一个例子:

    @Singleton
       class Foo:
           def __init__(self):
               print 'Foo created'
    
       f = Foo() # Error, this isn't how you get the instance of a singleton
    
       f = Foo.Instance() # Good. Being explicit is in line with the Python Zen
       g = Foo.Instance() # Returns already created instance
    
       print f is g # True
    

    这是代码:

    class Singleton:
        """
        A non-thread-safe helper class to ease implementing singletons.
        This should be used as a decorator -- not a metaclass -- to the
        class that should be a singleton.
    
        The decorated class can define one `__init__` function that
        takes only the `self` argument. Other than that, there are
        no restrictions that apply to the decorated class.
    
        To get the singleton instance, use the `Instance` method. Trying
        to use `__call__` will result in a `TypeError` being raised.
    
        Limitations: The decorated class cannot be inherited from.
    
        """
    
        def __init__(self, decorated):
            self._decorated = decorated
    
        def Instance(self):
            """
            Returns the singleton instance. Upon its first call, it creates a
            new instance of the decorated class and calls its `__init__` method.
            On all subsequent calls, the already created instance is returned.
    
            """
            try:
                return self._instance
            except AttributeError:
                self._instance = self._decorated()
                return self._instance
    
        def __call__(self):
            raise TypeError('Singletons must be accessed through `Instance()`.')
    
        def __instancecheck__(self, inst):
            return isinstance(inst, self._decorated)
    
  • 434

    我会把我扔到戒指里 . 这是一个简单的装饰 .

    from abc import ABC
    
    def singleton(real_cls):
    
        class SingletonFactory(ABC):
    
            instance = None
    
            def __new__(cls, *args, **kwargs):
                if not cls.instance:
                    cls.instance = real_cls(*args, **kwargs)
                return cls.instance
    
        SingletonFactory.register(real_cls)
        return SingletonFactory
    
    # Usage
    @singleton
    class YourClass:
        ...  # Your normal implementation, no special requirements.
    

    我认为它有一些其他解决方案的好处:

    • 它清晰简洁(我的眼睛; D) .

    • 它的动作是完全封装的 . 您无需更改 YourClass 实现的任何内容 . 这包括不需要为您的类使用元类(请注意,上面的元类是在工厂,而不是"real"类) .

    • 它不依赖猴子修补任何东西 .

    • 这对来电者来说是透明的:

    • 调用者仍然只是导入 YourClass ,它看起来像一个类(因为它),并且它们正常使用它 . 无需使呼叫者适应工厂功能 .

    • YourClass() 实例化仍然是您实现的 YourClass 的真实实例,而不是任何类型的代理,因此不会产生副作用 .

    • isinstance(instance, YourClass) 和类似的操作仍然按预期工作(虽然这个位确实需要abc,因此排除了Python <2.6) .

    我的一个缺点确实发生了:真正类的classmethods和staticmethods不能通过隐藏它的工厂类来透明地调用 . 我从来没有遇到过这种需求,但是通过在工厂上使用自定义元类来实现 __getattr__() 来委托对真实类的全部属性访问,可以很容易地解决这个问题 .

    一个相关的模式I 've actually found more useful (not that I' m说这些事情经常是必需的)是一个"Unique"模式,其中使用相同的参数实例化类导致返回相同的实例 . 即a "singleton per arguments" . 以上内容适应这一点,变得更加简洁:

    def unique(real_cls):
    
        class UniqueFactory(ABC):
    
            @functools.lru_cache(None)  # Handy for 3.2+, but use any memoization decorator you like
            def __new__(cls, *args, **kwargs):
                return real_cls(*args, **kwargs)
    
        UniqueFactory.register(real_cls)
        return UniqueFactory
    

    所有这一切,我同意一般的建议,如果你认为你需要其中一件事,你真的应该停下片刻,问自己是否真的这样做 . 99%的时间,YAGNI .

  • 6

    这个怎么样:

    def singleton(cls):
        instance=cls()
        cls.__new__ = cls.__call__= lambda cls: instance
        cls.__init__ = lambda self: None
        return instance
    

    将它用作应该是单例的类的装饰器 . 像这样:

    @singleton
    class MySingleton:
        #....
    

    这与另一个答案中的 singleton = lambda c: c() 装饰器类似 . 与其他解决方案一样,唯一的实例具有类的名称( MySingleton ) . 但是,使用此解决方案,您仍然可以通过执行 MySingleton() 从类中实际获得实例(实际上是唯一的实例) . 它还可以通过执行 type(MySingleton)() (也返回相同的实例)来阻止您创建其他实例 .

  • 0

    它与fab的答案略有相似,但并不完全相同 .

    单例合约不要求我们能够多次调用构造函数 . 由于单身人士应该只创造一次,不应该被视为仅创造一旦? "Spoofing"构造函数可能会损害易读性 .

    所以我的建议是这样的:

    class Elvis():
        def __init__(self):
            if hasattr(self.__class__, 'instance'):
                raise Exception()
            self.__class__.instance = self
            # initialisation code...
    
        @staticmethod
        def the():
            if hasattr(Elvis, 'instance'):
                return Elvis.instance
            return Elvis()
    

    这并不排除用户代码使用构造函数或字段 instance

    if Elvis() is King.instance:
    

    ...如果你确定 Elvis 尚未创建,那 King 已经 .

    但它鼓励用户普遍使用 the 方法:

    Elvis.the().leave(Building.the())
    

    要完成此操作,您还可以覆盖 __delattr__() 以在尝试删除 instance 时引发异常,并覆盖 __del__() 以使其引发异常(除非我们知道程序正在结束...)

    进一步改进


    感谢那些帮助评论和编辑的人,其中更受欢迎 . 虽然我使用Jython,但这应该更普遍,并且是线程安全的 .

    try:
        # This is jython-specific
        from synchronize import make_synchronized
    except ImportError:
        # This should work across different python implementations
        def make_synchronized(func):
            import threading
            func.__lock__ = threading.Lock()
    
            def synced_func(*args, **kws):
                with func.__lock__:
                    return func(*args, **kws)
    
            return synced_func
    
    class Elvis(object): # NB must be subclass of object to use __new__
        instance = None
    
        @classmethod
        @make_synchronized
        def __new__(cls, *args, **kwargs):
            if cls.instance is not None:
                raise Exception()
            cls.instance = object.__new__(cls, *args, **kwargs)
            return cls.instance
    
        def __init__(self):
            pass
            # initialisation code...
    
        @classmethod
        @make_synchronized
        def the(cls):
            if cls.instance is not None:
                return cls.instance
            return cls()
    

    注意事项:

    • 如果你没有从python2.x中的对象继承,你会得到一个旧式的类,它不使用 __new__

    • 装饰 __new__ 时必须使用@classmethod进行装饰,否则 __new__ 将是未绑定的实例方法

    • 这可以通过使用元类来改进,因为这将允许您使 the 成为类级属性,可能将其重命名为 instance

  • 0

    你可能永远不需要Python中的单例 . 只需在模块中定义所有数据和功能,即可拥有事实上的单例 .

    如果你真的必须有一个单身课程,那么我会选择:

    class My_Singleton(object):
        def foo(self):
            pass
    
    my_singleton = My_Singleton()
    

    使用:

    from mysingleton import my_singleton
    my_singleton.foo()
    

    其中mysingleton.py是您定义My_Singleton的文件名 . 这是有效的,因为在第一次导入文件后,Python不会重新执行代码 .

  • 1

    这个答案很可能不是你想要的 . 我想要一个单身,因为只有那个对象有它的身份,以便与之比较 . 就我而言,它被用作Sentinel Value . 答案非常简单,使任何对象 mything = object() 和python的性质,只有那个东西才会有它的身份 .

    #!python
    MyNone = object()  # The singleton
    
    for item in my_list:
        if item is MyNone:  # An Example identity comparison
            raise StopIteration
    
  • 70

    好吧,除了同意有关模块级全局的一般Pythonic建议,这个怎么样:

    def singleton(class_):
        class class_w(class_):
            _instance = None
            def __new__(class2, *args, **kwargs):
                if class_w._instance is None:
                    class_w._instance = super(class_w, class2).__new__(class2, *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(object):
        def __init__(self, text):
            print text
        @classmethod
        def name(class_):
            print class_.__name__
    
    x = MyClass(111)
    x.name()
    y = MyClass(222)
    print id(x) == id(y)
    

    输出是:

    111     # the __init__ is called only on the 1st time
    MyClass # the __name__ is preserved
    True    # this is actually the same instance
    
  • -2

    我不记得我在哪里找到了这个解决方案,但我从非Python专家的角度来看它是最“优雅的”:

    class SomeSingleton(dict):
        __instance__ = None
        def __new__(cls, *args,**kwargs):
            if SomeSingleton.__instance__ is None:
                SomeSingleton.__instance__ = dict.__new__(cls)
            return SomeSingleton.__instance__
    
        def __init__(self):
            pass
    
        def some_func(self,arg):
            pass
    

    我为什么喜欢这个?没有装饰器,没有元类,没有多重继承...如果你决定不再让它成为Singleton,只需删除 __new__ 方法 . 由于我是Python的新手(以及一般的OOP),我希望有人会直截了当地说明为什么这是一个糟糕的方法?

  • -1

    这个解决方案在模块级别引起了一些命名空间污染(三个定义而不仅仅是一个),但我发现它很容易理解 .

    我希望能够编写类似这样的内容(延迟初始化),但不幸的是,类在自己定义的主体中不可用 .

    # wouldn't it be nice if we could do this?
    class Foo(object):
        instance = None
    
        def __new__(cls):
            if cls.instance is None:
                cls.instance = object()
                cls.instance.__class__ = Foo
            return cls.instance
    

    由于这是不可能的,我们可以打破初始化和静态实例

    急切初始化:

    import random
    
    
    class FooMaker(object):
        def __init__(self, *args):
            self._count = random.random()
            self._args = args
    
    
    class Foo(object):
        def __new__(self):
            return foo_instance
    
    
    foo_instance = FooMaker()
    foo_instance.__class__ = Foo
    

    延迟初始化:

    急切初始化:

    import random
    
    
    class FooMaker(object):
        def __init__(self, *args):
            self._count = random.random()
            self._args = args
    
    
    class Foo(object):
        def __new__(self):
            global foo_instance
            if foo_instance is None:
                foo_instance = FooMaker()
            return foo_instance
    
    
    foo_instance = None
    
  • 54

    使用模块 . 它只导入一次 . 在其中定义一些全局变量 - 它们将是单例的'属性' . 添加一些函数 - 单例的'方法' .

  • -2
    class Foo(object):
         pass
    
    some_global_variable = Foo()
    

    模块只导入一次,其他一切都是过度思考 . 不要使用单例并尽量不使用全局变量 .

  • 13

    使用多种解决方案查看Stack Overflow问题Is there a simple, elegant way to define singletons in Python? .

    我'd strongly recommend to watch Alex Martelli'在python中讨论设计模式:part 1part 2 . 特别是,在第1部分中,他讨论了单身人士/共享状态对象 .

  • 3

    方法3似乎非常整洁,但如果您希望程序在Python 2Python 3中运行,则它不起作用 . 即使使用Python版本的测试来保护单独的变体也会失败,因为Python 3版本在Python 2中提供了语法错误 .

    感谢Mike Watkins:http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ . 如果您希望程序在Python 2和Python 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]
    
    MC = Singleton('MC', (object), {})
    
    class MyClass(MC):
        pass    # Code for the class implementation
    

    我认为赋值中的“对象”需要替换为“BaseClass”,但我没有尝试过(我已经尝试过代码如图所示) .

  • 19

    这是给你的单行:

    singleton = lambda c: c()
    

    这是你如何使用它:

    @singleton
    class wat(object):
        def __init__(self): self.x = 1
        def get_x(self): return self.x
    
    assert wat.get_x() == 1
    

    您的对象急切地被实例化 . 这可能是也可能不是你想要的 .

  • 2

    以前的答案是正确的,但我不同意作为方法1下的问题的一部分发布的声明“MyClass本身是一个函数,而不是类,所以你不能调用类方法” . 请参阅下面的示例,在MyClass中使用singleton标记装饰多次调用该方法 .

    另外,请注意这与发布的一些答案非常相似,并且基于python document,但它略有不同,因为类和函数的设计方式是它可以接收1或0个参数,但仍然是单例工作 .

    这是证明您可以多次调用singleton的方法,并显示仍然使用该类的一个实例,并且不会创建新对象 .

    #/usr/bin/env python
    
    def singleton(cls):
        instances = {}
        def getinstance(anyArgs=None):
            if cls not in instances:
                instances[cls] = cls(anyArgs)
            return instances[cls]
        return getinstance
    
    @singleton
    class MyClass:
        def __init__(self,count=None):
            print("print argument if any exists",count)
    
        def test(self, counter):
            # time.sleep(1000)
            print("-->",counter)
            return counter
    
    ### create two objects to see if we get a singleton behavior !
    a = MyClass(10000)
    a.test(1)
    b = MyClass()
    b.test(2)
    if a != b:
        print("this is not a singleton")
    
    #lets makesure it's still is the same object
    if a!=b:
        print("error")
    

    由于theheadofabroom(发布问题的人)给出了一些关于他原始问题的反馈,然后我根据他的反馈开始研究新的解决方案(我仍然保留了我之前的答案,因为我认为它可能对某些人有用,即使它是不是100%正是heheadofabroom所要求的) . 这是更新的答案:

    这是复制和粘贴它的代码:)

    #/usr/bin/env python
    from functools import wraps 
    
    def singleton(cls):
        instances = {}
        def getinstance(anyArgs=None):
            if cls not in instances:
                instances[cls] = cls(anyArgs)
                return instances[cls]
        return getinstance
    
    def add_function(cls):
        def outer_decorate_it(somefunction):
            @wraps(somefunction) 
            def wrapper( *args, **kwargs): 
                return somefunction(*args, **kwargs)
            setattr(cls, somefunction.__name__, wrapper)
            return somefunction
        return outer_decorate_it
    
    @singleton
    class MyClass():
        def __init__(self,count=None):
            print("print argument if any exists",count)
    
    @add_function(MyClass)
    def testit():
        print("It's me the function from the class")
    
    
    MyClass.testit()
    
  • 1

    使用元类

    我建议 Method #2 ,但你最好使用 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]
    
    class Logger(object):
        __metaclass__ = Singleton
    

    或者在Python3中

    class Logger(metaclass=Singleton):
        pass
    

    如果要在每次调用类时运行 __init__ ,请添加

    else:
                cls._instances[cls].__init__(*args, **kwargs)
    

    Singleton.__call__ 中的 if 语句 .

    关于元类的几句话 . 元类是 class of a class ;也就是说,一个类是 instance of its metaclass . 您可以使用 type(obj) 在Python中找到对象的元类 . 普通的新式类的类型为 type . 上面代码中的 Logger 将是 class 'your_module.Singleton' 类型,就像 Logger 的(唯一)实例将是 class 'your_module.Logger' 类型一样 . 当您使用 Logger() 调用logger时,Python首先会询问 LoggerSingleton 的元类,该怎么做,允许抢占实例创建 . 这个过程与Python通过执行 myclass.attribute 引用其中一个属性时通过调用 __getattr__ 要求类做什么一样 .

    元类本质上决定 what the definition of a class means 以及如何实现该定义 . 参见例如http://code.activestate.com/recipes/498149/,它基本上使用元类在Python中重新创建C风格的 struct . 线程What are your (concrete) use-cases for metaclasses in Python?也提供了一些示例,它们通常似乎与声明性编程有关,尤其是在ORM中使用 .

    在这种情况下,如果使用 Method #2 ,并且子类定义 __new__ 方法,则它将 executed every time 调用 SubClassOfSingleton() - 因为它负责调用返回存储实例的方法 . 使用元类,当创建唯一实例时,它将 only be called once . 你想 customize what it means to call the class ,这是由它的类型决定的 .

    一般来说, makes sense 使用元类来实现单例 . 单例是特殊的,因为 created only once ,而元类是自定义 creation of a class 的方式 . 如果您需要以其他方式自定义单例类定义,则使用元类会为您提供 more control .

    你的单身人士 won't need multiple inheritance (因为元类不是基类),但是对于使用多重继承的 subclasses of the created class ,你需要确保单例类是 first / leftmost ,其中一个元类重新定义 __call__ 这不太可能是一个问题 . 实例字典是 not in the instance's namespace 所以它不会意外覆盖它 .

    您还会听到单例模式违反了"Single Responsibility Principle" - 每个类都应该 only one thing . 这样,如果您需要更改另一个代码,您不必担心代码会搞乱一件事,因为它们是分开的并且是封装的 . 元类实现 passes this test . 元类负责 enforcing the pattern ,创建的类和子类不必是 aware that they are singletons . Method #1 未通过此测试,正如您在"MyClass itself is a a function, not a class, so you cannot call class methods from it."中所述

    Python 2和3兼容版本

    编写适用于Python2和3的内容需要使用稍微复杂的方案 . 由于元类通常是 type 类型的子类,因此可以使用它来在运行时动态创建中间基类,并将其作为其元类,然后将其用作public Singleton 基类的基类 . 这比解释更难解释,如下图所示:

    # works in Python 2 & 3
    class _Singleton(type):
        """ A metaclass that creates a Singleton base class when called. """
        _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]
    
    class Singleton(_Singleton('SingletonMeta', (object,), {})): pass
    
    class Logger(Singleton):
        pass
    

    这种方法的一个具有讽刺意味的方面是它使用子类来实现元类 . 一个可能的优点是,与纯元类不同, isinstance(inst, Singleton) 将返回 True .

    更正

    在另一个主题上,您可能已经注意到了这一点,但原始帖子中的基类实现是错误的 . _instances 需要 referenced on the class ,你需要使用 super() 或者你是 recursing ,而 __new__ 实际上是一个静态方法,你必须 pass the class to ,而不是类方法,因为它被调用时的实际类 hasn't been created . 所有这些事情对于元类实现也是如此 .

    class Singleton(object):
      _instances = {}
      def __new__(class_, *args, **kwargs):
        if class_ not in class_._instances:
            class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs)
        return class_._instances[class_]
    
    class MyClass(Singleton):
      pass
    
    c = MyClass()
    

    装饰师返回 class

    我最初写的是评论但是时间太长了,所以我会在这里添加 . Method #4 比其他装饰器版本更好,但是's more code than needed for a singleton, and it'并不清楚它的作用 .

    主要的问题源于这个类是什么's own base class. First, isn'如果一个类是一个几乎相同的类的子类,它的同名只存在于它的 __class__ 属性中,这很奇怪吗?这也意味着您无法使用 super() 定义 any methods that call the method of the same name on their base class ,因为它们会递归 . 这意味着您的类无法自定义 __new__ ,并且无法从需要 __init__ 调用它们的任何类派生 .

    何时使用单例模式

    您的用例是 one of the better examples 想要使用单例 . 你在其中一条评论中说"To me logging has always seemed a natural candidate for Singletons."你是 absolutely right .

    当人们说单身人士不好时,最常见的原因是他们是 implicit shared state . 虽然全局变量和顶级模块导入是 explicit 共享状态,但是传递的其他对象通常是实例化的 . 这是一个好点, with two exceptions .

    第一个,也就是在各个地方被提到的一个,就是当单身人士是 constant 时 . 使用全局常量,特别是枚举,被广泛接受,并且无论如何都被认为是理智的, none of the users can mess them up for any other user . 对于常数单例也是如此 .

    第二个例外,提到的更少,是相反的 - 当单例是 only a data sink 时,不是数据源(直接或间接) . 这就是为什么 Logger 感觉像是单身人士的用途 . 由于各种用户在其他用户关心的方式中都有 not changing the loggers ,因此有 not really shared state . 这否定了针对单例模式的主要论证,并使它们成为一个合理的选择,因为它们的任务是 ease of use .

    以下是http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html的引用:

    现在,有一种单身人士可以 . 这是一个单例,其中所有可到达的对象都是不可变的 . 如果所有对象都是不可变的,那么Singleton没有全局状态,因为一切都是常量 . 但是很容易将这种单体变成可变的单体,它是非常滑的斜率 . 因此,我也反对这些单身人士,不是因为他们不好,而是因为他们很容易变坏 . (作为旁注,Java枚举只是这些单例 . 只要你没有将状态放入枚举中就可以了,所以请不要 . )另一种半单可接受的单身人士是那些它们不会影响代码的执行,它们没有“副作用” . 记录是完美的例子 . 它载有单身人士和全球国家 . 这是可以接受的(因为它不会伤害你),因为无论是否启用给定的 Logger ,您的应用程序都不会有任何不同 . 此处的信息以一种方式流动:从您的应用程序到 Logger . 即使 Logger 是全局状态的,因为没有信息从 Logger 流入您的应用程序,因此 Logger 是可接受的 . 如果您希望测试断言某些内容已被记录,您仍应注入 Logger ,但总的来说,尽管状态已满,但 Logger 无害 .

  • -1

    代码基于Tolli's answer .

    #decorator, modyfies new_cls
    def _singleton(new_cls):
        instance = new_cls()                                              #2
        def new(cls):
            if isinstance(instance, cls):                                 #4
                return instance
            else:
                raise TypeError("I can only return instance of {}, caller wanted {}".format(new_cls, cls))
        new_cls.__new__  = new                                            #3
        new_cls.__init__ = lambda self: None                              #5
        return new_cls
    
    
    #decorator, creates new class
    def singleton(cls):
        new_cls = type('singleton({})'.format(cls.__name__), (cls,), {} ) #1
        return _singleton(new_cls)
    
    
    #metaclass
    def meta_singleton(name, bases, attrs):
        new_cls = type(name, bases, attrs)                                #1
        return _singleton(new_cls)
    

    说明:

    • 创建新类,继承自给定的 cls
      (它不会修改 cls 以防有人想要例如 singleton(list)

    • 创建实例 . 在覆盖 __new__ 之前,这很容易 .

    • 现在,当我们轻松创建实例时,使用之前定义的方法覆盖 __new__ .

    • 该函数仅在调用者期望的情况下返回 instance ,否则引发 TypeError .
      当有人试图从装饰类继承时,不满足条件 .

    • 如果__new __()返回cls的实例,那么新实例的__init __()方法将被调用,如__init __(self [,...]),其中self是新实例,其余参数与传递给__new __() .

    instance 已经初始化,因此函数替换 __init__ ,函数什么都不做 .

    See it working online

  • 1

    一个班轮(我不自豪,但它做的工作):

    class Myclass:
      def __init__(self):
          # do your stuff
          globals()[type(self).__name__] = lambda: self # singletonify
    

相关问题