2011-11-23 143 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 
>>> 

注意!如果您只需要實例化最後一級子類,此解決方案將有所幫助。你不能實例化抽象類。