如何适应Singleton模式?(弃用警告)

sum*_*mid 15 python singleton design-patterns deprecated

几年前,我在Duncan Booth的 Python中找到了Singleton模式的实现:

class Singleton(object):
    """
    Singleton class by Duncan Booth.
    Multiple object variables refers to the same object.
    http://web.archive.org/web/20090619190842/http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html#singleton-and-the-borg
    """
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                               cls, *args, **kwargs)
        return cls._instance
Run Code Online (Sandbox Code Playgroud)

问题还描述了" 在Python中定义单例的简单,优雅的方法吗? "

我通过子类别使用Singleton:
class Settings(Singleton)
class Debug(Singleton)

最近我对程序做了一些修改并得到了这个警告:

/media/KINGSTON/Sumid/src/miscutil.py:39: DeprecationWarning: 
object.__new__() takes no parameters
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

我找到了关于弃用的解释(由Guido 解释),__new__其中说参数根本没有使用.传递不需要的参数可能是错误的症状.

所以我决定清除参数:

class Singleton(object):
_instance = None

def __new__(cls):
    if not cls._instance:
        cls._instance = super(Singleton, cls).__new__()
    return cls._instance
Run Code Online (Sandbox Code Playgroud)

这导致以下异常:

Traceback (most recent call last):
 File "sumid.py", line 1168, in <module>
  settings = Settings()
 File "/media/KINGSTON/Sumid/src/miscutil.py", line 45, in __new__
  cls._instance = super(Singleton, cls).__new__()
 TypeError: object.__new__(): not enough arguments
Run Code Online (Sandbox Code Playgroud)

当我修改线路时cls._instance = super(Singleton, cls).__new__(cls),我会得到:

Traceback (most recent call last):
  File "sumid.py", line 1174, in <module>
    debug = Debug(settings)
TypeError: __new__() takes exactly 1 argument (2 given)
Run Code Online (Sandbox Code Playgroud)

Gimmel建议另一个解决方案:_instance = type.__new__(cls).对我来说它打破了继承:

Traceback (most recent call last):
  File "sumid.py", line 1168, in <module>
    settings = Settings()
  File "/media/KINGSTON/Sumid/src/miscutil.py", line 40, in __new__
    _instance = type.__new__(cls)
TypeError: type.__new__(Settings): Settings is not a subtype of type
Run Code Online (Sandbox Code Playgroud)

Menno Smits也有同样的问题.但我不明白建议的解决方案.而且我在相关代码中没有多重继承.

我没有尝试"在Python中定义单例的简单,优雅的方法吗?"中的另一个例子,但是一眼就看出它可能会遇到同样的问题.

我在一个程序中使用Singleton模式,我不想仅仅因为一个警告而完全重写它.因此,以下答案不会帮助我:

  • 单身人士错了.根本不要使用Singleton.
  • 使用Borg代替它,它更加pythonic.
  • 使用模块而不是类.

总之我会重复这个问题:
如何适应辛格尔顿在考虑的模式弃用警告影响最小,以现有的代码?

编辑: Line cls._instance = object.__new__(cls)在Child的init接受参数时引发TypeError:

class Child(Singleton):
    def __init__(self,param=None):
        print(param)
        print("Doing another stuff.")

ch = Child("Some stuff") 
Run Code Online (Sandbox Code Playgroud)

Dun*_*can 10

在构造对象时,需要删除正在传递的任何其他参数.将违规行更改为:

        cls._instance = object.__new__(cls)
Run Code Online (Sandbox Code Playgroud)

要么

        cls._instance = super(Singleton, cls).__new__(cls)
Run Code Online (Sandbox Code Playgroud)

虽然我认为你会对第一个完美(钻石继承和单身声音,好像它们不应该混合在一起).

PS我确实试过这个建议,它对我有用,所以我不知道它为什么不适合你.

编辑以响应@ dragonx的评论:正如评论中所指出的,object.__new__如果你传递,将抛出一个异常,*args, **kwargs因此超级调用不__new__应该包括任何参数cls.撰写原始文章时并非如此.当然,如果您选择将单例基于其他类型(例如a)tuple,则需要传递适当的参数.