在另一个类中初始化一个类,但只传递set属性

时间:2014-03-31 19:12:02

标签: python composition

我有一个类,它应该包含几个其他类作为其属性 - 我相信组合将是正确的术语。现在,我想初始化包含类的属性,具体取决于它们是否已在包含类中设置。在下面的示例中,我将使用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()

我想要实现的可能是一个糟糕的设计决定吗?

1 个答案:

答案 0 :(得分: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__))