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

时间:2011-06-07 10:40:07

标签: python design-patterns singleton 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

问题“Is there a simple, elegant way to define Singletons in 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)

我发现explanation(由Guido提供)关于__new__弃用,其中表示根本没有使用这些参数。传递不需要的参数可能是错误的症状。

所以我决定清除参数:

class Singleton(object):
_instance = None

def __new__(cls):
    if not cls._instance:
        cls._instance = super(Singleton, cls).__new__()
    return cls._instance

导致以下异常:

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

当我将该行修改为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)

Gimmel建议另一个solution_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

同样problem也有Menno Smits。但我不明白建议solution。此外,我在相关代码中没有多重继承。

我没有尝试另一个example“是否有一种简单,优雅的方式来定义Python中的Singletons?”,但是一眼就看出它可能会遇到同样的问题。

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

  • Singleton错了。根本不要使用Singleton。
  • 使用Borg代替它,它更加pythonic。
  • 使用模块而不是类。

总结我将重复这个问题:
如何调整Singleton 模式,并考虑弃用警告,并对现有代码影响最小

修改 当Child的init接受参数时,行cls._instance = object.__new__(cls)引发TypeError:

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

ch = Child("Some stuff") 

3 个答案:

答案 0 :(得分:9)

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

        cls._instance = object.__new__(cls)

        cls._instance = super(Singleton, cls).__new__(cls)

虽然我认为你对第一个没问题(钻石继承和单例声音,好像它们不应该混合在一起)。

P.S。我确实尝试了这个建议,它对我有用,所以我不知道它为什么不适合你。

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

答案 1 :(得分:1)

基于@Sven和@Duncan的答案,我发现了一个适合我的解决方案。问题实际上不在引发TypeError的代码行中,而是在__new__()方法的签名中。 object.__new__(cls)的调用应该没有* args,** kwargs,但它们必须保留在Singleton.__new__()定义中。这是修改过的Singleton:

class Singleton(object):
    """
    Singleton class by Duncan Booth.
    Multiple object variables refers to the same object.
    http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html
    """
   _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

这是子分类的一个例子(这是问题):

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

ch=Child('Some stuff')

我仍然不明白为什么Child __init__()的签名必须与Singleton的` new ()匹配,但此解决方案有效

答案 2 :(得分:0)

我发现这个模式在Python 3模式和成语源中描述。这肯定会有所帮助。我很想知道它是否能解决你的问题,虽然它可能会违反你问题中的最小影响条件。

Python 3: The Singleton