The Diamond Problem

Learn about the diamond problem and how to resolve it.

Overview

We can use multiple inheritance to add this new class as a parent of our existing Friend class. The tricky part is that we now have two parent __init__() methods, both of which need to be called. And they need to be called with different arguments. How do we do this? Well, we could start with a naive approach for the Friend class, also:

Press + to interact
class Friend(Contact, AddressHolder):
def __init__(
self,
name: str,
email: str,
phone: str,
street: str,
city: str,
state: str,
code: str,
) -> None:
Contact.__init__(self, name, email)
AddressHolder.__init__(self, street, city, state, code)
self.phone = phone

Problem in multiple inheritance

In this example, we directly call the __init__() function on each of the superclasses and explicitly pass the self argument. This example technically works; we can access the different variables directly in the class. But there are a few problems.

  • First, it is possible for a superclass to remain uninitialized if we neglect to explicitly call the initializer. That wouldn’t break this example, but it could cause hard-to-debug program crashes in common scenarios. We would get a lot of strange-looking AttributeError exceptions in classes where there’s clearly an __init__() method. It’s rarely obvious the __init__() method wasn’t actually used.

  • A more insidious possibility is a superclass being called multiple times because of the organization of the class hierarchy. Look at this inheritance diagram:

Press + to interact
Multiple inheritance implementation
Multiple inheritance implementation

The __init__() method from the Friend class first calls __init__() on the Contact class, which implicitly ...