2014-03-31 56 views
1

我有一個類,它應該包含幾個其他類作爲它的屬性 - 我相信組合是合適的術語。現在,我想初始化包含的類的屬性,具體取決於它們是否已在包含類中設置。在下面的例子中,我也只是覆蓋兩個小類別的默認值與None,我不想:在另一個類中初始化一個類,但只傳遞設置屬性

class OneAttribute: 
    def __init__(self,a=1): 
     self.a = a 

class TwoAttributes: 
    def __init__(self,b=2,c=3): 
     self.b = b 
     self.c = 3 

class SuperClass: 
    def __init__(self,a=None,b=None,c=None): 
     ''' 
     This would override the defaults in the 
     other two classes, which is bad. 
     ''' 
     self.one = OneAttribute(a=a) 
     self.two = TwoAttributes(b=b,c=c) 

我也可以這樣定義下面包含類,但這不是很好,也不擴展只是可怕:

Class SuperClass: 
    def __init__(self,a=None,b=None,c=None): 
     if a is not None: 
      self.one = OneAttribute(a=a) 
     else: 
      self.one = OneAttribute() 

     if b is not None and c is not None: 
      self.two = TwoAttributes(b=b, c=c) 
     elif b is not None: 
      self.two = TwoAttributes(b=b) 
     elif c is not None: 
      self.two = TwoAttributes(c=c) 
     else: 
      self.two = TwoAttributes() 

是什麼,我想,也許實現了糟糕的設計決策?

+0

爲什麼是de 'SuperClass'中的錯誤值與其他類中的錯誤值不同?你可以讓他們一樣嗎? – BrenBarn

+1

是'def __init __(self,a = 1,b = 2,c = 3):'一個選項?然後你可以分別調用'OneAttribute(a)'和'TwoAttributes(b,c)'。 – Hyperboreus

+1

你沒有提到的一件事是你可以將所有'if _不是None'條件移入子類'__init__'方法中。通過這種方式,您可以像第一個示例一樣保留'SuperClass'定義,並且只傳入子類可以處理的'None'或子類應該設置的值。 –

回答

2

一種解決方案是讓你的班級接受額外的關鍵字參數

class OneAttribute: 
    def __init__(self,a=1,**kwargs): 
     self.a = a 

class TwoAttributes: 
    def __init__(self,b=2,c=3,**kwargs): 
     self.b = b 
     self.c = c 

然後,你可以簡單地在容器類接受關鍵字參數

class SuperClass: 
    def __init__(self, **kwargs): 
     self.one = OneAttribute(**kwargs) 
     self.two = TwoAttributes(**kwargs) 

的缺點是,如果你通過一個額外的參數給其他兩個內部類將不會被檢測到。

避免這個問題是可能的,但需要一些黑魔法:第一,你只需要聲明的內部類和往常一樣:

class OneAttribute: 
    def __init__(self,a=1): 
     self.a = a 

class TwoAttributes: 
    def __init__(self,b=2,c=3): 
     self.b = b 
     self.c = c 

那麼你探索使用內省什麼參數,他們預計

def parms_of(f): 
    return f.__code__.co_varnames[:f.__code__.co_argcount] 

並只傳遞給內部類的構造函數

def filter_kwargs(kwargs, f): 
    s = set(parms_of(f)) 
    return dict((k, v) for k, v in kwargs.items() 
       if k in s) 

class SuperClass: 
    def __init__(self, **kwargs): 
     self.one = OneAttribute(**filter_kwargs(kwargs, OneAttribute.__init__)) 
     self.two = TwoAttributes(**filter_kwargs(kwargs, TwoAttributes.__init__)) 
+0

我想知道:爲什麼寫'f .__ code __。co_varnames [:f .__ code __。co_argcount]'而不是'f .__ code __。co_varnames'?在哪種情況下,您通過'f .__ code __。co_argcount'編制索引的結果不僅僅是打印所有var_names? – mSSM

+1

@mSSM:'co_varnames'是一個元組,它包含函數體中使用的所有本地名稱,而不僅僅是參數。函數參數始終是初始部分。 – 6502