Python composition: use one component class in multiple composite classes?

I have a class that is intended to be used as a component. I intentionally don’t want to inherit from this class to get access to its methods, because I want to implement composition in my codebase. I have multiple classes that need the methods from this component class. Is it then appropriate to use this class multiple times as a component in other composite classes?

If I understand it correctly you are asking about an OOP composition like:

class Person:
    given_name: str
    surname: str

class Team:
    manager: Person
    members: list[Person]

This is a completely common way of composition. I am not sure how you want to use the mentioned methods. If they do not fit into this scheme, let us know about more details.

@vbrozik, yes, I am asking about OOP composition. Your example is right on, even though you forgot to decorate both classes with the @dataclass decorator.

Now, make your example to include a plethora of such component classes (like the class Person is a component class in your example). Say, make your Team composite class to include 10 component classes, which consequentially means that you’d then need to pass 10 arguments to the Team composite class when instantiating it.

Would you say that 10 component classes is an overdose? At what point does it become an overdose?

(OOP composition overdose is my expression. It means to give a composite class so many component classes that a developer would feel it is either a bloated composite class or perhaps even a violation of the SOLID principles, specifically the Single Responsibility Principle one.)

No, I wanted to give you a minimal working example. Why should I use dataclasses for this? That is perfectly valid code without them. Test it in your Python and possibly with mypy:

person_john_smith = Person()
person_john_smith.given_name = 'John'
person_john_smith.surname = 'Smith'

You certainly do not always want to initialize all the object attributes from arguments. Maybe it is some misconception you have from the basic form of dataclasses? You will find out that some attributes are initialized independently from the arguments, some are initialized from constants or factories, some can be derived from other attributes, some can be initialized later…

Other points about composition:

  • In Python you are using composition always you are adding attributes into a class. In Python everything is an object. (Every variable binds to an object.)
  • Maybe contrary to your current point of view: composition allows you to make your classes smaller. It allows you to split classes:
# This class is too big
class BigClass:
    attr1: object
    attr2: object
    attr3: object
    attr4: object
    attr5: object
class SmallClass1:
    attr1: object
    attr2: object
    attr3: object

class SmallClass2:
    attr4: object
    attr5: object

# much better:
class BigClass:
    attr1: SmallClass1
    attr2: SmallClass2

In the beginning let the readability and maintainability of the code steer you. Imagine yourself half a year later when you forget everything about the code. How will you understand it? Imagine other people reading your code. Makes the logical structure of the code/attributes sense? Are not you creating “spaghetti code” etc…? Single responsibility principle - Wikipedia you mention is also certainly important.

There is much more to cover and it is not about Python. It is about OOP in general. I would recommend you reading a book about it.

1 Like

This might be a little late. But here is a great video that I came across on the subject
(might help others asking on the same subject):