2013-06-24 47 views
0

我想定義一個類AorB,這樣所有的A都是AorB的,而所有的B都是AorB的,而這些都是AorB的。當然,A和B應該是AorB的子類。問題出在AorB.__init__,當我無法說服自己它應該是別的東西。我可以定義一個AorB工廠,但如果可能的話,我寧願使用AorB構造函數。Python類的總和

class AorB: 
    def __init__(self,par): 
     if par: self=A(par) #! 
     else: self=B()  #! 
    @staticmethod 
    def from_par(par): 
     if par: return A(par) 
     else: return B() 
class A(AorB): 
    def __init__(self,par): 
     self.par=par 
class B(AorB): 
    def __init__(self): 
     pass 
print(
    AorB.from_par(5), 
    AorB.from_par(0), 
    AorB(5), 
    AorB(0), 
    sep="\n") 

我知道賦值給自己在這裏不起作用,但我只是想表現出意圖。正如我所說的,工廠(from_par)工作正常,我只想稱它爲AorB,而不是AorB.from_par

PS。我知道,__init__可能爲時已晚,自己的類型已經確定。隨意在你的答案中使用元類。我該學習一些有用的東西。 :-)

回答

3

你不能,而不是__init__。一旦調用__init__實例已創建

你想要一個工廠功能來代替:

class AorB: pass 

class A(AorB): 
    def __init__(self,par): 
     self.par=par 

class B(AorB): 
    def __init__(self): 
     pass 

def AorB(par): 
    return A(par) if par else B() 

從一個角度API點,沒有區別; AorB是可調用的,它可以產生A()B()實例。

其他可能的路由涉及定義一個__new__函數,而不是;這是類構造函數:

class AorB: 
    def __new__(cls, par=None): 
     if cls is not AorB: return super().__new__(cls) 
     return super().__new__(A) if par else super().__new__(B) 

class A(AorB): 
    def __init__(self, par): 
     self.par = par 

class B(AorB): 
    def __init__(self, par=None): 
     pass 

這只是一個更復雜的工廠函數,真的。注意__new__方法返回的基於par的子類之一的super().__new__的結果,所以無論AB將傳遞一個par參數,它們是否想要一個與否。

if cls is not AorB行需要允許直接實例化A()B();如果這不是要求,那麼可以省略該行,並且只使用AorB工廠類。

+0

「工廠功能」對我來說不夠好。據我所知,你只是用def AorB覆蓋了AorB類。因此,實例(AorB(5),AorB)引發TypeError。 :-(我懷疑'__init__'已經太晚了,可以'__new__'和metaclasses有什麼幫助嗎? – Veky

+0

@ user1875565:是的,但是更多的參與和醜陋 –

+0

醜陋在於觀察者眼中。:-) One更多的問題:可以通過讓A和B自己調用'super().__ new__'的'__new__'來避免'_constructing'?另外,我寧願不使用默認參數,真實情況更復雜,A和B構造函數已經使用它們的「None」的公平份額。 :-) – Veky