Basis van overerving in Python
Overerving is een van de fundamenten van objectgeoriënteerd programmeren (OOP). Het stelt één class (de child class) in staat om attributen en methoden over te nemen van een andere class (de parent class). Deze eigenschap is essentieel voor hergebruik van code en vereenvoudigt onderhoud, waardoor je makkelijker schaalbare en efficiënte programma’s bouwt.
Parent- en child-classes definiëren
Voordat we verder gaan, bekijken we de relatie tussen parent- en child-classes.
Parent class
Laten we beginnen met de parent class. Een parent class is de basisklasse waaruit child-classes afleiden. Die kapselt gedeelde attributen en methoden in.
In Python definieer je een parent class zo:
class ParentClass:
def __init__(self, attributes):
# Initialize attributes
pass
def method(self):
# Define behavior
pass
Child class
Een child class erft attributen en methoden van de parent class. Zo kan die de functionaliteit uit de parent class gebruiken. Onderstaande code laat zien hoe een child class attributen en methoden erft van een parent class:
class ChildClass(ParentClass):
def additional_method(self):
# Define new behavior
pass
Met deze eenvoudige syntaxis kan de child class de functionaliteit uit de parent class gebruiken én uitbreiden.
Een parent class en een child class maken
We maken een praktisch voorbeeld met Person als parent en Student als child.
De parent class maken
De class Person bevat gedeelde attributen en een methode om informatie te tonen:
# Defining the Parent Class
class Person:
def __init__(self, name, id):
self.name = name
self.id = id
def display_info(self):
return f"Name: {self.name}, ID: {self.id}"
De child class maken
De class Student erft van Person en voegt een nieuwe methode study toe.
# Defining the Child Class
class Student(Person):
def study(self):
return f"{self.name} is studying."
Laten we de parent- en child-classes testen.
# Creating and Testing Instances
student = Student("Samuel", 102)
print(student.display_info())
print(student.study())
Name: Samuel, ID: 102
Samuel is studying.
Wat gebeurt hier?
-
De class
Studentgebruikt de methode__init__vanPersonomnameenidte initialiseren. -
De methode
studyis uniek voor de classStudenten breidt de functionaliteit uit. -
De methode
display_infois rechtstreeks geërfd vanPerson.
Soorten overerving in Python
Overerving in Python laat classes attributen en gedrag van andere classes erven, wat hergebruik en een schoon ontwerp bevordert, zoals we eerder al bespraken. In deze sectie bekijken we de verschillende typen overerving in Python: single, multiple, hiërarchische en hybride overerving als afzonderlijke categorieën.
Single inheritance
Single inheritance treedt op wanneer een child class van één enkele parent class erft, waardoor die de functionaliteit van de parent kan uitbreiden. Dit is handig wanneer een objecttype eigenschappen deelt met een bredere categorie, maar ook extra attributen of gedrag nodig heeft.
Het voorbeeld dat ik eerder uitwerkte, was single inheritance, maar laten we er nu wat beter naar kijken: in een schoolsysteem delen alle personen, waaronder studenten, docenten en medewerkers, gemeenschappelijke gegevens zoals name en ID. Studenten hebben echter ook studiegegevens, zoals cijfers en ingeschreven vakken. Met single inheritance kun je een Person class maken voor gedeelde attributen en die uitbreiden met een Student class voor studiegegevens.

Single inheritance. Afbeelding door de auteur
Hier is een goed voorbeeld van het bovenstaande scenario:
class Person:
"""Represents a general person with basic details."""
def __init__(self, name, id):
self.name = name
self.id = id
def get_details(self):
return f"Name: {self.name}, ID: {self.id}"
class Student(Person):
"""Represents a student, extending the Person class to include academic details."""
def __init__(self, name, id, grade, courses):
super().__init__(name, id)
self.grade = grade
self.courses = courses
def get_details(self):
return f"Name: {self.name}, ID: {self.id}, Grade: {self.grade}, Courses: {', '.join(self.courses)}"
# Example usage in a school system
student = Student("Samuel", 5678, "B+", ["Math", "Physics", "Computer Science"])
print(student.get_details())
Name: Samuel, ID: 5678, Grade: B+, Courses: Math, Physics, Computer Science
De class Student erft de methode get_details() van Person maar breidt die uit met grade en courses. Dit is een goed voorbeeld van hoe single inheritance bijdraagt aan modulaire code.
Multiple inheritance
Multiple inheritance stelt een child class in staat om van meer dan één parent class te erven en zo attributen en gedrag te combineren. Dit kan tot conflicten leiden, die Python oplost met de method resolution order (MRO).

Multiple inheritance. Afbeelding door de auteur
Kijk maar:
class Person:
def get_details(self):
return "Details of a person."
class Athlete:
def get_skill(self):
return "Athletic skills."
class Student(Person, Athlete):
pass
# Example usage
student = Student()
print(student.get_details())
print(student.get_skill())
Details of a person.
Athletic skills.
We zien dat de class Student attributen en methoden erft van zowel Person als Athlete. Zonder extra werk heeft Student toegang tot de methode get_details() uit de parent class Person en de methode get_skill() uit de parent class Athlete. We combineren effectief functionaliteit uit meerdere bronnen.
Erven van meerdere classes kan echter tot conflicten leiden. Wat als beide parent classes een methode of attribuut met dezelfde naam definiëren? Ik noemde eerder de method resolution order; daarover nu iets meer. De method resolution order bepaalt in welke volgorde classes worden doorzocht naar methoden en attributen. De MRO volgt een depth-first, van links-naar-rechts benadering.
Je kunt de MRO van een class bekijken met het attribuut __mro__ of de methode mro():
print(Student.__mro__)
(<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Athlete'>, <class 'object'>)
Multilevel, hiërarchische en hybride overerving
Python ondersteunt ook complexere overervingsstructuren. Ik laat deze ideeën zien met hetzelfde voorbeeld.
Multilevel inheritance
Multilevel inheritance ontstaat wanneer een child class erft van een andere child class, die op zijn beurt erft van een parent class. Dit creëert een keten van overerving.

Multilevel inheritance. Afbeelding door de auteur
Hier is een goed voorbeeld:
class Person:
def __init__(self, name, id):
self.name = name
self.id = id
def get_details(self):
return f"Name: {self.name}, ID: {self.id}"
class Student(Person):
def __init__(self, name, id, grade):
super().__init__(name, id)
self.grade = grade
def get_details(self):
return f"Name: {self.name}, ID: {self.id}, Grade: {self.grade}"
class GraduateStudent(Student):
def __init__(self, name, id, grade, thesis_title):
super().__init__(name, id, grade)
self.thesis_title = thesis_title
def get_details(self):
return f"Name: {self.name}, ID: {self.id}, Grade: {self.grade}, Thesis: {self.thesis_title}"
# Example usage
grad_student = GraduateStudent("Charlie", 91011, "A", "AI in Healthcare")
print(grad_student.get_details())
Name: Charlie, ID: 91011, Grade: A, Thesis: AI in Healthcare
Hier voegt elke class in de keten iets toe: Person beheert namen en ID’s, Student voegt cijfers toe, en GraduateStudent introduceert een thesis. Dankzij super().__init__() hergebruiken we de initialisatielogica zonder code te dupliceren. Efficiënt, netjes en elke trede van de “overervingsladder” werkt.
Hiërarchische overerving
Bij hiërarchische overerving erven meerdere child-classes van één parent class, zodat gedrag gedeeld kan worden terwijl subclasses unieke attributen hebben.

Hiërarchische overerving. Afbeelding door de auteur
Laten we samen een goed voorbeeld bekijken:
class Person:
def __init__(self, name, id):
self.name = name
self.id = id
def get_details(self):
return f"Name: {self.name}, ID: {self.id}"
class Student(Person):
def __init__(self, name, id, grade):
super().__init__(name, id)
self.grade = grade
def get_details(self):
return f"Name: {self.name}, ID: {self.id}, Grade: {self.grade}"
class Teacher(Person):
def __init__(self, name, id, subject):
super().__init__(name, id)
self.subject = subject
def get_details(self):
return f"Name: {self.name}, ID: {self.id}, Subject: {self.subject}"
# Example usage
student = Student("Samuel", 5678, "B+")
teacher = Teacher("Dr. Smith", 1234, "Math")
print(student.get_details())
print(teacher.get_details())
Name: Samuel, ID: 5678, Grade: B+
Dr. Smith, ID: 1234, Subject: Math
Hier fungeert de class Person als fundament met gemeenschappelijke attributen en methoden (name, id en get_details). De classes Student en Teacher breiden dit uit met hun eigen eigenschappen (grade en subject) en passen get_details aan hun context aan.
Met deze aanpak blijft gedeelde functionaliteit op één plek (de class Person), terwijl gespecialiseerd gedrag netjes is ingekapseld in de subclasses.
Hybride overerving
Hybride overerving combineert meerdere overervingstypen, zoals multilevel of multiple inheritance, om complexere relaties te modelleren.

Hybride overerving. Afbeelding door de auteur
Hier is een voorbeeld dat de complexiteit van hybride overerving laat zien.
# Base class
class Person:
def __init__(self, name, id):
self.name = name
self.id = id
def get_details(self):
return f"Name: {self.name}, ID: {self.id}"
# Intermediate class inheriting from the base class
class Employee(Person):
def __init__(self, name, id, position):
super().__init__(name, id)
self.position = position
def get_position(self):
return f"Position: {self.position}"
# Another independent base class
class Athlete:
def __init__(self, sport):
self.sport = sport
def get_sport(self):
return f"Sport: {self.sport}"
# Derived class combining Employee and Athlete
class Student(Employee, Athlete):
def __init__(self, name, id, position, grade, sport):
Employee.__init__(self, name, id, position)
Athlete.__init__(self, sport)
self.grade = grade
def get_grade(self):
return f"Grade: {self.grade}"
# Example usage
student = Student("Samuel", 1234, "Intern", "A", "Soccer")
print(student.get_details()) # From Person
print(student.get_position()) # From Employee
print(student.get_grade()) # From Student
print(student.get_sport()) # From Athlete
Name: Samuel, ID: 1234
Position: Intern
Grade: A
Sport: Soccer
In dit voorbeeld laat de class Student hybride overerving zien door attributen en methoden te erven van zowel Employee (dat zelf erft van Person) als Athlete. Dit combineert hiërarchische overerving (waar Employee erft van Person) en multiple inheritance (waar Student erft van zowel Employee als Athlete).
Voordelen van overerving in Python
Nu is het tijd om de sterke en zwakke punten te bekijken:
Voordelen van overerving
-
Hergebruik: met overerving schrijf je code één keer in de parent class en hergebruik je die in child-classes. In het voorbeeld kunnen zowel
FullTimeEmployeealsContractorde methodeget_details()erven van de parent classEmployee. -
Eenvoud: overerving modelleert relaties duidelijk. Een goed voorbeeld is de class
FullTimeEmployeedie “is een” type van de parent classEmployee. -
Schaalbaarheid: je kunt nieuwe features of child-classes toevoegen zonder bestaande code te beïnvloeden. Zo voegen we eenvoudig een nieuwe child class
Interntoe.
Mogelijke beperkingen van overerving
-
Complexiteit: niet verrassend, maar te veel overervingsniveaus maken code lastig te volgen. Als een
Employeebijvoorbeeld te veel child-classes heeft, zoalsManager,Engineer,Intern, enz., kan dat verwarrend worden. -
Afhankelijkheid: wijzigingen in een parent class kunnen onbedoeld alle subclasses beïnvloeden. Als je bijvoorbeeld
Employeeaanpast, kan datFullTimeEmployeeofContractorbreken. -
Misbruik: overerving gebruiken wanneer het niet past, kan ontwerpen onnodig ingewikkeld maken. Je wilt bijvoorbeeld geen oplossing maken waarin
Carerft vanBoatalleen ommove()te hergebruiken. Die relatie slaat nergens op.
Geavanceerde technieken voor overerving in Python
Nu we de basis hebben behandeld, kijken we naar enkele geavanceerde technieken. Deze technieken, zoals methoden overschrijven, super(), abstracte basisklassen en polymorfisme, vergroten de flexibiliteit van je code en maken geavanceerdere ontwerppatronen mogelijk.
Methoden overschrijven in Python
Met het overschrijven van methoden kan een child class een specifieke implementatie geven voor een methode die al in de parent class is gedefinieerd. Dit is handig wanneer het geërfde gedrag niet volledig voldoet aan de eisen van de child class.
class Person:
def __init__(self, name, id):
self.name = name
self.id = id
def get_details(self):
return f"Name: {self.name}, ID: {self.id}"
class Student(Person):
def __init__(self, name, id, grade):
super().__init__(name, id)
self.grade = grade
# Overriding the get_details method
def get_details(self):
return f"Name: {self.name}, ID: {self.id}, Grade: {self.grade}"
# Example usage
student = Student("Samuel", 1234, "A")
print(student.get_details())
Name: Samuel, ID: 1234, Grade: A
Hier overschrijft de class Student de methode get_details() uit de class Person met een eigen implementatie. Zo kan de child class eigen gedrag hebben met dezelfde methodenaam.
Waarom overschrijven we? Omdat we geërfd gedrag willen aanpassen en de functionaliteit van een parent-methode willen afstemmen op de unieke eisen van een child class.
super() gebruiken voor initialisatie van de parent
De functie super() wordt gebruikt om vanuit een child class methoden in de parent class aan te roepen. Dit is vooral handig als je de functionaliteit van een parent-methode wilt uitbreiden of aanpassen, zoals de constructor __Init__().
Waarom gebruiken we super()? Omdat we de constructor van de parent class willen aanroepen en initialiseren én de parent class niet expliciet willen benoemen. Dit is vooral nuttig bij multiple inheritance.
class Person:
def __init__(self, name, id):
self.name = name
self.id = id
class Student(Person):
def __init__(self, name, id, grade):
# Using super() to initialize the parent class
super().__init__(name, id)
self.grade = grade
# Example usage
student = Student("Samuel", 5678, "B+")
print(student.name)
print(student.id)
print(student.grade)
Samuel
5678
B+
Hier gebruikt de class Student super().__init__(name, id) om de methode __init__ van de parent class Person aan te roepen, zodat de code om de attributen name en id te initialiseren niet herhaald hoeft te worden. De child class voegt vervolgens het attribuut grade toe, dat specifiek is voor Student.
Abstracte basisklassen (ABCs)
Een abstracte basisklasse (ABC) is een class waarmee je niet direct objecten kunt maken. Die is bedoeld om een gemeenschappelijke set methoden te definiëren die andere classes moeten implementeren. ABC’s zijn handig als je zeker wilt weten dat bepaalde methoden altijd aanwezig zijn in child-classes.
from abc import ABC, abstractmethod
class Person(ABC):
@abstractmethod
def get_details(self):
pass
class Student(Person):
def __init__(self, name, id, grade):
self.name = name
self.id = id
self.grade = grade
def get_details(self):
return f"Name: {self.name}, ID: {self.id}, Grade: {self.grade}"
# Example usage
student = Student("Hamilton", 7890, "A-")
print(student.get_details())
Name: Hamilton, ID: 7890, Grade: A-
De class Person is hier een abstracte class die vereist dat elke child class de methode get_details() implementeert. Deze methode wordt later geïmplementeerd door de child class Student.
Polymorfisme
Polymorfisme betekent veelvormigheid. In Python zorgt het ervoor dat verschillende classes dezelfde methodenaam kunnen gebruiken, maar elk die methode op een andere manier kan implementeren.
Polymorfisme helpt om code te schrijven die met objecten van verschillende classes kan werken, zelfs als die classes verschillend gedrag hebben:
class Person:
def get_details(self):
return "Details of a person."
class Student(Person):
def get_details(self):
return "Details of a student."
class Teacher(Person):
def get_details(self):
return "Details of a teacher."
# Example usage
def print_details(person):
print(person.get_details())
student = Student()
teacher = Teacher()
print_details(student)
print_details(teacher)
Details of a student.
Details of a teacher.
In dit voorbeeld kan de functie print_details() elk object van het type Person accepteren, maar wordt de juiste methode get_details() aangeroepen afhankelijk van of het object een Student of een Teacher is.
Veelgemaakte fouten en best practices
Overerving is krachtig, maar je gebruikt het snel verkeerd. Ik deel wat ideeën om er het meeste uit te halen.
Vermijd verrassingen met overschreven methoden
Als een child class een methode van de parent overschrijft, kan het gedrag veranderen.
Als de parent class Employee bijvoorbeeld een methode calculate_pay() heeft en de child class Manager die overschrijft zonder alle scenario’s te overwegen, kan dat tot foutieve loonsberekeningen leiden.
De best practice is in dit geval: test overschreven methoden grondig en documenteer hun gedrag.
Kiezen tussen overerving en compositie
Dit artikel gaat dan wel over overerving, maar dat is niet altijd de juiste aanpak. Soms past compositie beter: je bouwt classes door objecten te combineren in plaats van ze uit te breiden.
Om het verschil kernachtig te verwoorden:
-
Overerving gaat over “is-een”-relaties. Bijvoorbeeld: een
Manageris eenEmployee. -
Compositie gaat over “heeft-een”-relaties. Bijvoorbeeld: een
Carheeft eenEngine.
Wanneer kies je dan voor compositie? Gebruik compositie als de relatie niet strikt hiërarchisch is en/of wanneer je de onderlinge afhankelijkheid tussen classes wilt verminderen.
Of anders gezegd: waar overerving relaties modelleert, richt compositie zich op functionaliteit. Ter hulp, denk hieraan:
-
Gebruik overerving wanneer objecten van nature hiërarchisch zijn. Bijvoorbeeld
Animal > Bird > Parrot. -
Gebruik compositie wanneer objecten functionaliteit delen maar niet verwant zijn. Bijvoorbeeld: een
PrinterenScannergebruiken beide eenDeviceManager.
Vermijd diepe overervingsketens
Diepe overervingsketens (veel niveaus van parent-childrelaties) maken je code lastig leesbaar en onderhoudbaar. Dat is een probleem, want wijzigingen in een parent class kunnen onbedoeld veel child-classes raken. Bovendien wordt debuggen complexer doordat gedrag over meerdere niveaus is verspreid.
De best practice hier is: houd hiërarchieën ondiep. Overweeg compositie (zoals eerder genoemd) of splits een keten op in aparte hiërarchieën als die te diep wordt.
Conclusie
Overerving is een belangrijke pijler van objectgeoriënteerd programmeren en stelt je als developer in staat om herbruikbare, modulaire en schaalbare code te maken. Als je overerving beheerst, wordt het eenvoudiger om complexe systemen te vereenvoudigen.
Een goede manier om je begrip te verdiepen is door overervingsstructuren in je eigen projecten te bouwen. Begin simpel en experimenteer daarna met complexere hiërarchieën om te zien hoe ze in de praktijk werken.
Als je graag nog dieper duikt, bekijk dan onze cursus Programming Paradigm Concepts voor een diepere uitleg over overerving en andere ideeën. Onze Python Developer-carrièretrack is ook een goede bron met een compleet pad naar geavanceerde programmeerskills voor softwareontwikkeling.

Ervaren dataprofessional en schrijver die graag ambitieuze experts in de dataruimte wil versterken.
Veelgestelde vragen over overerving in Python
Wat is overerving in Python?
Overerving in Python is een mechanisme waarmee een class attributen en methoden van een andere class kan erven, wat hergebruik van code en hiërarchische class-structuren bevordert.
Hoe werkt overerving in Python?
Overerving in Python werkt door een nieuwe class te definiëren die attributen en methoden overneemt van een bestaande class, waardoor hiërarchische class-structuren mogelijk zijn.
Welke typen overerving zijn er in Python?
Python ondersteunt verschillende soorten overerving, waaronder single, multiple, multilevel en hiërarchische overerving.
Wat is het verschil tussen single en multiple inheritance in Python?
Single inheritance heeft één parent class, terwijl multiple inheritance toestaat dat een class van meerdere parent classes erft.
Hoe implementeer je overerving in Python?
Implementeer overerving door een nieuwe class te definiëren die een parent class specificeert in de definitie, met de syntaxis class ChildClass(ParentClass):.
Wat zijn de voordelen van overerving in Python?
Overerving bevordert hergebruik van code, maakt hiërarchische class-structuren mogelijk en ondersteunt polymorfisme, waardoor code flexibeler en beter onderhoudbaar wordt.
Hoe implementeer je multiple inheritance in Python?
Multiple inheritance implementeer je door een class te definiëren die erft van meer dan één basisklasse. Python bepaalt de methodevolgorde met de method resolution order (MRO).

Stel, je bouwt een softwaresysteem met meerdere gebruikersrollen, zoals studenten, docenten en beheerders. Deze rollen delen gemeenschappelijke attributen zoals naam en ID, maar hebben ook functionaliteit die uniek voor hen is. In plaats van code te dupliceren, kun je met overerving gedeeld gedrag definiëren in een parent class en dit uitbreiden in gespecialiseerde child classes.
In dit artikel verkennen we overerving in Python, met zowel basis- als gevorderde concepten zoals het overschrijven van methoden en de functie
super(), een ingebouwde functie die een tijdelijk object van de superclass retourneert, zodat je toegang krijgt tot diens methoden zonder de parent class expliciet te noemen. Maak je geen zorgen als dat nog niet meteen duidelijk is; hieronder leggen we alles uit.