1

I'm attempting to use a composition over inheritance design concept, and I've been storing the creator and main_actor of every component. This overall looks very repetitive and ugly, so I'm wondering if there's a way to make it nicer.

class ComponentA:
    def __init__(self, **kwargs):
        self.creator    = kwargs['creator']
        self.main_actor = kwargs['main_actor']
        self.b          = ComponentB(creator=self, main_actor=self.main_actor)
        self.c          = ComponentC(creator=self, main_actor=self.main_actor)

        # instead of that, i want to achieve the same, 
        # without the eye sore of the repetitive kwargs:

        self.b = ComponentB()
        self.c = ComponentC()

        # perhaps with metaclasses? or a function? 

        self.b = make(ComponentB)
        self.c = make(ComponentC)
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
domoxbr
  • 13
  • 3

2 Answers2

0

I'm not sure how pythonic this is, but you might try the following:

class ComponentA:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

        self.b = self.make(ComponentB)
        self.c = self.make(ComponentC)

    def make(self, component):
        return component(creator=self, main_actor=self.main_actor)

class ComponentB:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

class ComponentC:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

a = ComponentA(creator=None, main_actor='MAIN_ACTOR')

print(a.b.main_actor)


>>> 'MAIN_ACTOR'

edit: See Is self.__dict__.update(**kwargs) good or poor style? for more information on this solution.

Cory Nezin
  • 1,551
  • 10
  • 22
0

Both composition and inheritance have their place. To avoid your repetition in your component classes I'd use inheritance thus:

class Component(object):

    def __init__(self, **kwargs):
        for name in ('creator', 'main_actor'):
            setattr(self, name, kwargs[name])

        component_class = type(self)
        for attr in dir(component_class):
            if not attr.startswith('__'):
                sub_component_class = getattr(component_class, attr)
                if issubclass(sub_component_class, Component):
                    setattr(self, attr, sub_component_class(**{**kwargs, 'creator': self}))


class ComponentB(Component):
    pass


class ComponentC(Component):
    pass


class ComponentA(Component):
    b = ComponentB
    c = ComponentC

# In [0]: a = ComponentA(creator='me', main_actor='fred')
# 
# In [1]: a.creator
# Out[1]: 'me'
# 
# In [2]: a.b
# Out[2]: <__main__.ComponentB at 0x7f6def403550>
# 
# In [3]: a.b.creator
# Out[3]: <__main__.ComponentA at 0x7f6def47cc18>
# 
# In [4]: a.b.main_actor
# Out[4]: 'fred'
# 
# In [5]: a.c.main_actor
# Out[5]: 'fred'
Paul Whipp
  • 16,028
  • 4
  • 42
  • 54