Python-klassen en -objecten: OOP-zelfstudie met echte voorbeelden
Leer objectgeoriënteerde Python door iets echts te bouwen. Creëer klassen, begrijp jezelf en __init__, deel gedrag met overerving, bescherm gegevens met eigenschappen en weet wanneer een klasse het verkeerde hulpmiddel is.
- Een klasse is een blauwdruk, en een object is één ding dat daaruit is opgebouwd.
__init__stelt elk nieuw object in, enselfverwijst naar dat object.- Attributen die voor de klasse zijn ingesteld, worden gedeeld. Attributen ingesteld op
selfbehoren tot één object. - Gebruik
@dataclassvoor klassen die gegevens bevatten en geef de voorkeur aan eenvoudige functies als er geen status is om te behouden.
Naarmate een script groeit, geef je uiteindelijk dezelfde groep variabelen door tussen functies, en wordt het moeilijk om te bepalen welke gegevens bij welke logica horen. Python-klassen en -objecten lossen dit op door gegevens en gedrag in één eenheid te bundelen.
In deze tutorial bouwen we stap voor stap een kleine bankrekening op en voegen we elk OOP-idee pas toe als het een probleem oplost. We hebben elk voorbeeld uitgevoerd op Python 3.13, en de getoonde uitvoer is afkomstig van die run. Als je nieuw bent in de taal, lees dan eerst onze Python-tutorial voor beginners.
Wat zijn klassen en objecten?
Een klasse beschrijft wat iets is en wat het kan doen. Een object, ook wel instance genoemd, is een specifiek object dat op basis van die beschrijving is gemaakt. “Account” is een klasse, terwijl Asha’s account en Ben’s account twee objecten zijn.
| Termijn | Betekenis | Voorbeeld |
|---|---|---|
| Klasse | De blauwdruk | Rekening |
| Object of exemplaar | Er is één ding van gemaakt | a = Account("Asha") |
| Kenmerk | Gegevens over het object | a.balance |
| Methode | Een functie in de klas | a.deposit(50) |
Je gebruikt al die tijd voorwerpen. In Python zijn strings, lijsten en zelfs functies objecten, daarom kun je "hello".upper() schrijven.
Je eerste les
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("amount must be positive")
self.balance += amount
return self.balance
a = Account("Asha", 100)
b = Account("Ben")
a.deposit(50)
print(a.balance, b.balance)
# 150 0
__init__ wordt automatisch uitgevoerd wanneer u een object maakt, en stelt de startstatus in. Het deponeren in a raakte b niet, omdat elk object zijn eigen gegevens heeft. Merk op dat de methode het saldo ook beschermt tegen een slechte waarde. In onze gids voor Python-uitzonderingsafhandeling wordt raise uitgebreider uitgelegd.
Wat is zelf?
self is eenvoudigweg het object waaraan een methode werkt. Wanneer je a.deposit(50) schrijft, roept Python in feite Account.deposit(a, 50) aan, waarbij het object als eerste argument wordt doorgegeven. Zo kan één methodedefinitie elk object dienen.
De naam self is eerder een sterke conventie dan een trefwoord, maar gebruik deze altijd. Het vergeten ervan in een methodedefinitie is de meest voorkomende beginnersfout en levert een verwarrende boodschap op over het aantal argumenten.
Klassekenmerken versus instantiekenmerken
Een attribuut dat rechtstreeks in de hoofdtekst van de klasse is ingesteld, wordt door alle objecten gedeeld. Eén set op self hoort alleen bij dat object. Dit voorbeeld laat zien hoe zoekopdrachten zich gedragen:
class Account:
interest_rate = 0.04 # class attribute
def __init__(self, owner, balance=0):
self.owner = owner # instance attribute
self.balance = balance
a = Account("Asha", 100)
b = Account("Ben")
print(a.interest_rate, b.interest_rate) # 0.04 0.04
Account.interest_rate = 0.05
print(a.interest_rate, b.interest_rate) # 0.05 0.05
a.interest_rate = 0.09
print(a.interest_rate, b.interest_rate, Account.interest_rate)
# 0.09 0.05 0.05
Die laatste regel verrast mensen. Toewijzing via a veranderde de gedeelde waarde niet. Het creëerde een nieuw instance-attribuut op a dat klasse één verbergt. Python kijkt eerst naar het object en vervolgens naar de klasse.
Speciale (dunder)methoden
Methoden met dubbele onderstrepingstekens zorgen ervoor dat uw objecten kunnen werken met de ingebouwde functies van Python. Zonder deze geeft het afdrukken van een account een nutteloos geheugenadres weer. Door er twee toe te voegen, krijgt het een leesbare vorm:
def __str__(self):
return f"{self.owner}: {self.balance}"
def __repr__(self):
return f"Account({self.owner!r}, {self.balance})"
print(a) # Asha: 150
print([a, b]) # [Account('Asha', 150), Account('Ben', 0)]
| Methode | Getriggerd door |
|---|---|
__init__ |
Een object maken |
__str__ |
print(obj), str(obj) |
__repr__ |
Debuggen, of het in een lijst weergeven |
__eq__ |
een == b |
__len__ |
len(obj) |
__add__ |
een + b |
Erfenis
Door overerving kan een nieuwe klasse een bestaande klasse hergebruiken en alleen veranderen wat verschilt. Hier is Savings een Account met een extra instelling:
class Savings(Account):
def __init__(self, owner, balance=0, limit=3):
super().__init__(owner, balance)
self.limit = limit
def __str__(self):
return f"{super().__str__()} (savings)"
s = Savings("Chitra", 500)
s.deposit(100)
print(s, isinstance(s, Account), s.limit)
# Chitra: 600 (savings) True 3
super() roept de versie van de ouder aan, zodat de installatielogica niet wordt herhaald. deposit werd overgenomen zoals het was, en __str__ werd overschreven om een label toe te voegen. Gebruik alleen overerving voor een echte ‘is een’-relatie. Als een klasse alleen maar iets nodig heeft, zoals een auto die een motor nodig heeft, geef hem dat object dan als attribuut. Dit staat bekend als compositie en is doorgaans flexibeler dan diepe overervingsketens.
Polymorfisme
Polymorfisme betekent dat verschillende objecten op hun eigen manier op dezelfde methodeaanroep kunnen reageren. De belcode hoeft niet het exacte type te kennen:
class Square:
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return round(3.14159 * self.radius ** 2, 2)
for shape in [Square(3), Circle(2)]:
print(type(shape).__name__, shape.area())
# Square 9
# Circle 12.57
Deze twee klassen delen niet eens een ouder. Het maakt Python alleen maar uit dat het object een area-methode heeft, een aanpak die bekend staat als duck-typing. Als u later een Triangle toevoegt, hoeft u de lus niet te wijzigen.
Inkapseling en eigenschappen
Python heeft geen echt privé-attributen en vertrouwt in plaats daarvan op conventies. Een enkel onderstrepingsteken, zoals in _price, vertelt andere ontwikkelaars “dit is intern, raak het niet aan”. Als u waarden wilt controleren wanneer ze zijn ingesteld, gebruikt u een property, die er van buitenaf uitziet als een gewoon attribuut:
class Product:
def __init__(self, price):
self.price = price
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("price cannot be negative")
self._price = value
p = Product(100)
p.price = 150
print(p.price) # 150
p.price = -5 # ValueError: price cannot be negative
Dit betekent dat u kunt beginnen met een gewoon attribuut en later validatie kunt toevoegen zonder code te wijzigen die de klasse gebruikt. Schrijf de methoden get_price() en set_price() dus niet uit gewoonte, zoals in Java. De @ syntaxis hier is een decorateur, die we uitleggen in Python-decorateurs uitgelegd.
Klassemethoden en statische methoden
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
@classmethod
def from_fahrenheit(cls, f):
return cls(round((f - 32) * 5 / 9, 1))
@staticmethod
def is_freezing(celsius):
return celsius <= 0
Temperature.from_fahrenheit(212).celsius # 100.0
Temperature.is_freezing(-3) # True
| Typ | Eerste argument | Gebruik het voor |
|---|---|---|
| Instantiemethode | zelf |
Werken met de gegevens van één object |
@classmethod |
cls |
Alternatieve constructeurs |
@staticmethod |
Geen | Helpers gerelateerd aan de klas |
Dataklassen
Als een klas voornamelijk gegevens bevat, is het met de hand schrijven van __init__, __repr__ en __eq__ vervelend. @dataclass genereert ze op basis van typeannotaties:
from dataclasses import dataclass, field
@dataclass
class Item:
name: str
price: int
tags: list = field(default_factory=list)
print(Item("Pen", 10))
print(Item("Pen", 10) == Item("Pen", 10))
# Item(name='Pen', price=10, tags=[])
# True
Tip: Niet alles heeft een les nodig. Als het geen toestand en slechts één gedrag heeft, is een gewone functie eenvoudiger. Voor eenvoudige zoekopdrachten kan een woordenboek voldoende zijn. Bereik een klasse wanneer data en de regels die deze beschermen duidelijk bij elkaar horen.
Veel voorkomende fouten
Een veranderlijk klassenattribuut gebruiken
Dit is een klassieke bug. De lijst is per klasse gedefinieerd, dus alle winkelwagens delen deze:
class Cart:
items = [] # shared by every cart!
def add(self, item):
self.items.append(item)
c1, c2 = Cart(), Cart()
c1.add("pen")
print(c2.items)
# ['pen']
Maak het aan in __init__ met self.items = [], zodat elk object zijn eigen lijst krijgt.
Andere veel voorkomende fouten
selfvergeten. Schrijfself.balance, nietbalance, interne methoden.- Vergeten
super().__init__(). Het kind mist dan attributen die door de ouder zijn ingesteld. - Grote klassen bouwen. Een klasse die alles doet, is moeilijk te testen. Verdeel het op basis van verantwoordelijkheid.
- Diepe erfenis. Twee niveaus zijn meestal voldoende, en de compositie is vaak duidelijker.
- Geen tests schrijven. Klassen met regels zijn eenvoudig te testen, zoals onze pytest-tutorial laat zien met behulp van een klein karretje.
Tot slot
Objectgeoriënteerde Python komt neer op het groeperen van gegevens met het gedrag dat deze beschermt. Begin met __init__, methoden en __str__, en voeg vervolgens overerving en eigenschappen toe als je een probleem tegenkomt dat ze oplossen. Neem als volgende stap een script dat overal dezelfde paar variabelen doorgeeft en verander ze in één kleine klasse.
Veelgestelde vragen
Wat is het verschil tussen een klasse en een object?
Een klasse is de definitie of blauwdruk. Een object is een specifieke instantie die ervan is gemaakt, met zijn eigen gegevens. Eén klasse kan veel objecten maken.
Wat doet __init__ in Python?
Het is de initialisatiefunctie, die automatisch wordt uitgevoerd wanneer u een object maakt. Meestal worden de startkenmerken van het object ingesteld op basis van de argumenten die u doorgeeft.
Wat is zelf in Python?
self verwijst naar het object waarop een methode wordt aangeroepen. Python geeft het automatisch door en laat de methode de attributen van dat object lezen en wijzigen.
Wat zijn de vier pijlers van OOP?
Het zijn inkapseling, abstractie, overerving en polymorfisme. Samen helpen ze je data te bundelen met gedrag, details te verbergen en code te hergebruiken.
Wanneer moet ik een klasse gebruiken in plaats van een functie?
Gebruik een klasse wanneer gegevens en gedrag bij meerdere bewerkingen bij elkaar horen. Voor één staatloze bewerking is een gewone functie eenvoudiger en gemakkelijker te testen.
Blijf leren
Hulp nodig met testen, WordPress of SEO?
We helpen teams betere software te leveren en hun sites te laten groeien. Vertel ons waar u mee bezig bent en wij stellen een duidelijke volgende stap voor.
Meer handleidingen over testen, AI en moderne ontwikkeling
Genoten van dit artikel? Kies een onderwerp en ga direct naar onze nieuwste tutorials.
AI-hallucinaties uitgelegd: waarom taalmodellen dingen verzinnen en hoe ze te verminderen
AI-hallucinaties uitgelegd: wat ze zijn, waarom taalmodellen ze produceren, veelvoorkomende typen, hoe je ze kunt verminderen met aarding en aanwijz…
Lees artikel →DevOpsOmgevingsvariabelen uitgelegd: .env-bestanden, geheimen en configuratie goed gedaan
Omgevingsvariabelen uitgelegd met Python-voorbeelden die we hebben uitgevoerd: ze lezen en instellen, waarom elke waarde een string is, .env-bestand…
Lees artikel →SoftwareontwikkelingAPI-snelheidsbeperking uitgelegd: algoritmen, headers en afhandeling van 429-fouten
API-snelheidsbeperking uitgelegd met een simulatie die we hebben uitgevoerd: token-bucket, vast venster, schuifvenster, 429 reacties, headers van sn…
Lees artikel →TestautomatiseringSpotten in Python: unittest.mock, patch en de fouten die tests doen liegen
Spotten in Python met unittest.mock, getest: Mock en return_value, side_effect, patchen waar een naam wordt gebruikt, spec en autospec, spotdatums e…
Lees artikel →SoftwaretestenCodedekking uitgelegd: lijn versus filiaaldekking en wat 100% werkelijk betekent
Codedekking uitgelegd met een echte dekking.py-run: dekking van lijnen, vertakkingen en condities, een rapport lezen, waarom 100% dekking nog steeds…
Lees artikel →Databases & SQLDELETE versus TRUNCATE versus DROP in SQL: verschillen, terugdraaien en wanneer elk te gebruiken
DELETE versus TRUNCATE versus DROP uitgelegd met geteste SQL: wat elk verwijdert, terugdraaien, triggers, identiteitsreset, snelheid en hoe PostgreS…
Lees artikel →Databases & SQLSQL-weergaven uitgelegd: creëer, gebruik en vermijd de valkuilen, met voorbeelden
SQL-weergaven uitgelegd met query's die we hebben uitgevoerd: een weergave maken, live resultaten, kolommen verbergen, prestaties, bijwerkbare en ge…
Lees artikel →SoftwareontwikkelingTypeScript-interface versus type: echte verschillen, getest met de compiler
TypeScript-interface versus type, gecontroleerd met de echte compiler: wat beide kunnen doen, wat slechts één kan doen, samenvoegen van declaraties,…
Lees artikel →SoftwareontwikkelingPython *args en **kwargs uitgelegd: flexibele functies met duidelijke voorbeelden
Python *args en **kwargs uitgelegd met code die we hebben uitgevoerd: in- en uitpakken, parametervolgorde, argumenten die alleen trefwoorden en posi…
Lees artikel →SoftwareontwikkelingPython Lambda-functies: syntaxis, echt gebruik en wanneer u ze niet moet gebruiken
Python lambda-functies uitgelegd met code die we hebben uitgevoerd: syntaxis, sorteren met sleutel, kaart en filter, sluitingen, de laat-bindende va…
Lees artikel →Kunstmatige intelligentieWat zijn AI-agenten? Hoe ze werken, met een eenvoudige agentloop die u kunt uitvoeren
Wat zijn AI-agenten? Een duidelijke gids voor de agentenlus, tools, geheugen en vangrails, met een kleine Python-lus die we hebben uitgevoerd, echte…
Lees artikel →DevOpsMonitoring versus waarneembaarheid: het echte verschil, met logboeken, statistieken en sporen
Monitoring versus waarneembaarheid uitgelegd: bekende en onbekende fouten, logboeken, statistieken en sporen, een walkthrough voor afrekenincidenten…
Lees artikel →DevOpsDocker-volumes versus bindingsmounts: bewaar containergegevens op de juiste manier
Docker-volumes versus bind-mounts uitgelegd: waarom containergegevens verdwijnen, benoemde volumes, bind-mounts, tmpfs, Compose-voorbeelden, back-up…
Lees artikel →TestautomatiseringTDD versus BDD: belangrijkste verschillen, één functie die op beide manieren is gebouwd en wanneer deze moet worden gebruikt
TDD versus BDD uitgelegd met één kortingsfunctie die in beide richtingen is gebouwd: rood-groen-refactor met code die we hebben uitgevoerd, gegeven-…
Lees artikel →SoftwaretestenGebruikersacceptatietesten (UAT): proces, checklist en echte voorbeelden
Gebruikersacceptatietesten uitgelegd: wie voert het uit, hoe het verschilt van QA, een proces in zeven stappen, een UAT-testcase-sjabloon, een check…
Lees artikel →Databases & SQLSQL NULL-waarden uitgelegd: IS NULL, COALESCE, NULLIF en de te vermijden vallen
SQL NULL-waarden uitgelegd met query's die we hebben uitgevoerd: logica met drie waarden, IS NULL, COALESCE, NULLIF, hoe aggregaten, joins en sorter…
Lees artikel →Databases & SQLSQL CASE WHEN-instructie: syntaxis, echte voorbeelden en veelvoorkomende fouten
SQL CASE WHEN uitgelegd met vragen die we hebben uitgevoerd: eenvoudige en doorzochte formulieren, volgorde van de voorwaarden, draaipunten met SUM,…
Lees artikel →SoftwareontwikkelingWat is JWT? JSON-webtokens uitgelegd met een werkend voorbeeld
Wat is JWT? JSON Web Tokens uitgelegd: de drie delen, een token gebouwd en waarmee is geknoeid in de code die we hebben uitgevoerd, JWT versus sessi…
Lees artikel →SoftwareontwikkelingJavaScript-gebeurtenislus uitgelegd: call-stack, microtaken en timers met voorbeelden
De JavaScript-gebeurtenislus uitgelegd met code die we hebben uitgevoerd: call-stack, taak- en microtask-wachtrijen, waarom setTimeout 0 niet onmidd…
Lees artikel →SoftwareontwikkelingPython-generatoren en opbrengst uitgelegd: bespaar geheugen met echte voorbeelden
Python-generatoren en opbrengst uitgelegd met code die we hebben uitgevoerd: hoe ze pauzeren en hervatten, gemeten geheugenbesparingen, pijplijnen, …
Lees artikel →Kunstmatige intelligentieWat zijn inbeddingen? Vectoren en cosinusovereenkomst eenvoudig uitgelegd
Wat zijn insluitingen? Een gids in duidelijke taal over vectoren, cosinusovereenkomst en semantisch zoeken, met een klein voorbeeld dat we hebben ui…
Lees artikel →DevOpsImplementatie van blauwgroen versus kanarie: verschillen, afwegingen en hoe te kiezen
Blauw-groen versus kanarie-implementatie uitgelegd: hoe elk werkt, kosten, risico's en terugdraaien, stabiele gebruikersbucket die we hebben getest,…
Lees artikel →TestautomatiseringSchilferige tests: wat de oorzaak ervan is en hoe u ze voorgoed kunt oplossen
Zwakke tests uitgelegd met demo's die we hebben uitgevoerd: de belangrijkste oorzaken, hoe je er een kunt bevestigen en diagnosticeren, goede oploss…
Lees artikel →SoftwaretestenBelastingtesten versus stresstesten: verschillen, statistieken en k6-voorbeelden
Belastingtesten versus stresstesten uitgelegd: wat elk bewijst, piek- en soak-tests, de statistieken die er toe doen, waarom gemiddelden misleiden, …
Lees artikel →SoftwaretestenTestcase versus testscenario: belangrijkste verschillen, voorbeelden en wanneer deze te gebruiken
Testcase versus testscenario uitgelegd: duidelijke definities, een tabel naast elkaar, één functie voor het opnieuw instellen van wachtwoorden, over…
Lees artikel →Databases & SQLOptimalisatie van SQL-query's: lees uitvoeringsplannen en repareer langzame query's, met timing
Optimalisatie van SQL-query's getest op een miljoen rijen: lees uitvoeringsplannen, voeg de juiste indexen toe, repareer niet-sargeerbare filters, g…
Lees artikel →Databases & SQLSQL UNION versus UNION ALL: verschillen, voorbeelden en geteste prestaties
SQL UNION versus UNION ALL uitgelegd met de query's die we hebben uitgevoerd: duplicaten, de regels volgen beide, een echte databug, gemeten prestat…
Lees artikel →SoftwareontwikkelingJavaScript Fetch API-tutorial: GET, POST, foutafhandeling en time-outs
Een JavaScript Fetch API-tutorial getest tegen een lokale server: GET en POST, waarom 404 niet gooit, een herbruikbare helper, queryreeksen, time-ou…
Lees artikel →SoftwareontwikkelingPython-bestandsverwerking: lezen, schrijven, CSV, JSON en pathlib met voorbeelden
Het verwerken van Python-bestanden uitgelegd met code die we hebben uitgevoerd: open modi, met het lezen van grote bestanden, CSV, JSON, pathlib, bi…
Lees artikel →SoftwareontwikkelingPython-klassen en -objecten: OOP-zelfstudie met echte voorbeelden
Python-klassen en -objecten uitgelegd met code die we hebben uitgevoerd: __init__, methoden, klasse versus instantie-attributen, overerving, eigensc…
Lees artikel →Kunstmatige intelligentieWat is een groot taalmodel? Hoe LLM's werken, uitgelegd zonder de hype
Wat is een groot taalmodel? LLM's uitgelegd in duidelijke taal: tokens, inbedding, aandacht, training, temperatuur- en contextvensters, een kleine d…
Lees artikel →DevOpsLinux-opdrachten voor beginners: de essentiële terminalgids met voorbeelden
Linux-opdrachten voor beginners, gegroepeerd op taak: navigatie, bestanden, logboeken bekijken, grep, pipelines, machtigingen, processen en archieve…
Lees artikel →TestautomatiseringSelenium versus toneelschrijver: belangrijkste verschillen, code vergeleken en welke te kiezen
Selenium versus Playwright vergeleken: architectuur, wachten, browser- en taalondersteuning, debuggen, dezelfde test in beide tools, migratieadvies …
Lees artikel →SoftwaretestenEquivalentiepartitionering: testontwerptechniek uitgelegd met uitgewerkte voorbeelden
Equivalentiepartitionering uitgelegd: hoe je geldige en ongeldige partities kunt vinden, uitgewerkte voorbeelden voor leeftijden, wachtwoorden en ko…
Lees artikel →SoftwaretestenErnst versus prioriteit bij het testen van software: verschillen, matrix en echte voorbeelden
Ernst versus prioriteit bij het testen van software uitgelegd: duidelijke definities, een vierwegmatrix met voorbeelden, niveauschalen, wie deze bep…
Lees artikel →Databases & SQLTutorial voor SQL-subquery's: typen, gecorreleerde subquery's en BESTAAN met voorbeelden
Een SQL-subquery-tutorial met query's die we hebben uitgevoerd: scalaire, IN-, FROM- en SELECT-subquery's, gecorreleerde subquery's, EXISTS, de NOT …
Lees artikel →Databases & SQLSQL-transacties en ACID uitgelegd: COMMIT-, ROLLBACK- en isolatieniveaus
SQL-transacties en ACID uitgelegd met een bankoverschrijving die we hebben uitgevoerd: COMMIT, ROLLBACK, savepoints, locks, isolatieniveaus, dirty r…
Lees artikel →SoftwareontwikkelingGit merge vs rebase: verschillen, voorbeelden en wanneer je wat gebruikt
Git merge vs rebase uitgelegd met echte logoutput, een vergelijkingstabel, de gouden regel van rebase en een veilige teamwerkwijze.
Lees artikel →SoftwareontwikkelingPython list comprehension: syntaxis, voorbeelden en wanneer je het vermijdt
Python list comprehension uitgelegd: syntaxis, filteren, if-else, geneste lussen, gemeten tijden en wanneer een gewone for-lus beter is.
Lees artikel →Databases & SQLSQL JOIN uitgelegd met voorbeelden (Inner, Left, Right, Full)
Begrijp SQL joins stap voor stap met voorbeeldtabellen en queries: INNER, LEFT, RIGHT, FULL, CROSS en SELF, plus veelgemaakte fouten en prestatietips.
Lees artikel →