2014-03-31 52 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