2011-11-23 103 views
3

我的想法是任何一个对象都应该存在于Singleton类的所有子类中。 我一直在尝试的代码和结果矩阵如下。矩阵似乎在子类的情况下工作正常。我走错路了吗?它是否会在父类对象和子类对象的情况下发生什么?python单例类可以被继承吗?

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

class A(Singleton): 
    def __new__(cls, *args, **kwargs): 
     super(A, cls).__new__(cls, *args, **kwargs) 

class B(Singleton): 
    def __new__(cls, *args, **kwargs): 
     super(B, cls).__new__(cls, *args, **kwargs) 

class C(B): 
    def __new__(cls, *args, **kwargs): 
     super(B, cls).__new__(cls, *args, **kwargs) 


if __name__ == '__main__': 
    s1=Singleton() 
    s2=Singleton() 
    if(id(s1)==id(s2)): 
     print "Same" 
    else: 
     print "Different" 

''' 
I got a result matrix for s1 and s2 
      |************ s2 **************************|   
s1   |Singleton() |A()  | B()  | C()  | 
===========|==========================================| 
Singleton()|Same  |Different|Different|Different| 
A()  |Different |Same  |Same  |Same  | 
B()  |Different |Same  |Same  |Same  | 
C()  |Different |Same  |Same  |Same  | 
''' 
+2

单例本身就等同于一个全局变量,只是用另外的代码模糊了这个事实,这些代码可能会出错。为什么不只是做'class A(object):...'然后用'a = A()'立即创建一个全局实例?您会看到**看起来像单个全局实例的单个全局实例,并且它在完全相同的范围内可用。如果懒惰的初始化是你想要的,那么有办法实现那些实际上*看起来像这就是你正在做的事情。 – Ben

+0

如果你修复了你的子类不返回任何东西的错误,你会得到非常奇怪的行为。如果你做's1 = Singleton()'然后's2 = A()',那么它们都是同一个对象('Singleton'的一个实例),但是如果你做's1 = A()',那么's2 = Singleton()'它们将是不同的对象(分别是'A'和'Singleton'的一个实例)。 – Ben

+0

这意味着在你的程序的某个较远的部分,'A()。method_of_a()'将会工作或抛出一个异常(或者莫名其妙地调用一个超类实现),这取决于“Singleton”是否已经被实例化。我无法想象这是怎样的理想行为;你打算用这个层次的单例类来做什么? – Ben

回答

3

代码看起来不错,但它没有意义接一个单值的一类和它的子类共享。子类的全部点与父类和兄弟子类有所不同。对我来说,每个类没有自己独特的单例实例似乎很奇怪。

3

没有一个子类的__new__()方法有明确的return语句,所以它们都返回None。这就是为什么他们的新实例都是一样的。有了这个代码,他们将同Singleton()太:

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

class A(Singleton): 
    def __new__(cls, *args, **kwargs): 
     return super(A, cls).__new__(cls, *args, **kwargs) 

class B(Singleton): 
    def __new__(cls, *args, **kwargs): 
     return super(B, cls).__new__(cls, *args, **kwargs) 

class C(B): 
    def __new__(cls, *args, **kwargs): 
     return super(C, cls).__new__(cls, *args, **kwargs) 

它甚至不是必要定义__new__()的子类:

class A(Singleton): 
    pass 

class B(Singleton): 
    pass 

class C(B): 
    pass 
+0

请注意,使用这段代码,如果我直接实例化一个Singleton,(不通过子类),那么它将在Singleton上设置_instance。这意味着所有进一步实例化的子类都将在它们的MRO中找到一个非'无'cls._实例',并且将返回它,而不是创建它们的实例。 – Ben

+1

我明白这是理想的行为。 –

+0

我怀疑,虽然我认为这个缺陷是真的在设计中,而不是在你的代码中。我无法想象这种行为会有用的合理情况,而不是错误。我认为海报可能不打算直接实例化Singleton(或者创建Singleton子类的更多子类)。 – Ben

0

我解决了这个问题抽象类的帮助。在我的样子:

from abc import ABCMeta, abstractmethod 


class BasicClass(object): 
    __metaclass__ = ABCMeta 

    instance = None 

    def __new__(cls, *args, **kwargs): 
     if not cls.instance: 
      cls.instance = super(BasicClass, cls).__new__(
            cls, *args, **kwargs) 

     return cls.instance 

    @abstractmethod 
    def action(self): 
     pass#do smthing 


class FirstLevelChild(BasicClass): 
    __metaclass__ = ABCMeta 

    @abstractmethod 
    def action(self): 
     pass#do smthing in this or other abstract method 
     # also pearent method can be called with help of super 

class SecondLevelChild1(FirstLevelChild): 
    def action(self): 
     pass#do smthing unique for this class 
     # in this or other abstract method 
     # also pearent method can be called with help of super 

class SecondLevelChild2(FirstLevelChild): 
    def action(self): 
     pass#do smthing unique for this class 
     # in this or other abstract method 
     # also pearent method can be called with help of super 

让检查

>>> a1 = SecondLevelChild1() 
>>> a2 = SecondLevelChild1() 
>>> b1 = SecondLevelChild2() 
>>> b2 = SecondLevelChild2() 
>>> a1 == b1 
False 
>>> a1 ==a2 
True 
>>> b1 == b2 
True 
>>> 

注意!如果您只需要实例化最后一级子类,此解决方案将有所帮助。你不能实例化抽象类。