Ga naar hoofdinhoud

Privémethoden in Python uitgelegd

Leer wat privémethoden in Python zijn, de syntaxis, hoe en wanneer je ze gebruikt in je projecten met voorbeelden, en best practices.
· 9 min lezen

Verken met AI

In objectgeoriënteerd programmeren (OOP), een aanpak voor softwareontwerp, gebruiken we “objecten” om entiteiten uit de echte wereld te modelleren. Een object is een datastructuur met attributen (data) en methoden (functies) die op die data werken. Complexe systemen kunnen makkelijker te ontwerpen zijn met objecten.

Leer meer over de basis en de software-engineeringconcepten achter OOP door te starten met onze cursus objectgeoriënteerd programmeren met Python.

Encapsulatie is een fundamenteel concept in OOP. Het betekent dat je de data en de methoden van een object groepeert en de details verbergt voor de buitenwereld. Zie encapsulatie als een proces dat een ‘capsule’ (een object) creëert met zijn eigen data en manieren om die te manipuleren.

Het belangrijkste doel van encapsulatie is om:

  • Rechtstreekse toegang tot de data te voorkomen (dataintegriteit).
  • Het systeem te vereenvoudigen door alleen te tonen wat nodig is (abstractie).

Privémethoden zijn cruciaal om deze encapsulatie te bereiken door de interne implementatiedetails van een klasse te verbergen.

Door een methode privé te maken, laat je andere programmeurs weten dat deze methode niet bedoeld is om direct te worden aangeroepen. Dit kan bugs en fouten voorkomen door ervoor te zorgen dat de interne status van een object alleen op gecontroleerde manieren kan worden gewijzigd.

Hier introduceren we privémethoden, de syntaxis om ze te definiëren, hoe je ze implementeert met praktijkvoorbeelden en de best practices voor het gebruik ervan.

Wat zijn privémethoden?

Privémethoden in objectgeoriënteerd programmeren (OOP) zijn functies binnen een klasse die uitsluitend voor intern gebruik zijn bedoeld. Ze kapselen de functionaliteit van een klasse in, zodat de interne werking afgeschermd blijft van externe interactie.

Deze encapsulatie zorgt voor een laag van abstractie, waardoor de klasse de controle behoudt over zijn interne toestand en gedrag, en zijn implementatie kan wijzigen zonder externe code die erop vertrouwt te beïnvloeden.

In Python geef je volgens de conventie privémethoden aan door de methodenaam te laten voorafgaan door een enkele underscore (_) of dubbele underscores (__). Dit is een hint voor ontwikkelaars over de beoogde scope van de methode en is slechts een conventie.

Hoewel deze conventie geen strikte privacy afdwingt zoals in sommige andere talen, is het binnen de Python-community een gerespecteerde manier om het beoogde gebruik van de methode te signaleren. Later gaan we dieper op deze aspecten in.

De syntaxis van privémethoden

Er zijn twee verschillende manieren om privémethoden te definiëren; we bekijken ze aan de hand van voorbeelden.

We kunnen een privémethode definiëren met een enkele underscore vóór de functienaam:

class MyClass:
   def _private_method(self):
       print("This is a private method")

Deze definitie is slechts een conventie voor programmeurs, want de functie is nog steeds van buiten de klasse toegankelijk, al wordt dat niet aanbevolen.

Als dit de eerste keer is dat je over klassen in Python hoort, raden we je aan om eerst onze beginnersvriendelijke tutorial over Classes te bekijken.

Laten we een object maken en proberen de gemaakte privémethode te benaderen:

# Creating an object
obj = MyClass()

# Accessing from outside
obj._private_method()  # Not recommended to call directly, but possible

Er is nog een syntaxis voor het definiëren van privémethoden in Python met dubbele underscores. Die ziet er zo uit:

class MyClass:
   def __private_method(self):
       print("This is a private method")

obj = MyClass()
# obj.__private_method()  # This will raise an AttributeError

Als we proberen de privémethode van buiten de klasse te benaderen, wordt er een AttributeError opgegooid, wat aangeeft dat deze niet rechtstreeks via de functienaam kan worden aangeroepen.

Samengevat de syntaxis van privémethoden in Python:

  • Enkele underscore: puur een conventie voor programmeurs, kan van buiten de functie worden benaderd.
  • Dubbele underscore: kan niet van buiten de functie worden benaderd met alleen de functienaam. Het is nog steeds toegankelijk via “name mangling”, wat we later in deze tutorial zullen zien.

Privémethoden in Python implementeren

Als praktijkvoorbeeld nemen we een veilige en gebruiksvriendelijke BankAccount-klasse om financiële transacties voor een gebruiker te beheren. De vereisten voor bankrekeningen zijn:

  • De klasse moet het saldo van de rekeninghouder inkapselen, zodat er kan worden gestort en opgenomen, terwijl wordt gewaarborgd dat het saldo niet rechtstreeks van buiten de klasse kan worden gemanipuleerd.
  • De klasse moet veilige overboekingen tussen rekeningen faciliteren, waarbij het saldo van de ontvangende rekening wordt bijgewerkt zonder het interne mechanisme voor saldomodificatie bloot te geven.
  • De oplossing moet voldoen aan de principes van objectgeoriënteerd programmeren, met name encapsulatie en abstractie, om de integriteit van de gegevens van de rekening te waarborgen en een duidelijke, eenvoudige interface te bieden voor interactie met de rekening.

Natuurlijk heeft een bankrekening meer functionaliteiten, zoals saldocontrole, valutaconversie en renteafhandeling — maar om het eenvoudig te houden, negeren we die in onze implementatie.

Laten we deze oplossing implementeren en de code begrijpen.

class BankAccount:
   def __init__(self, account_holder, initial_balance=0):
       self.account_holder = account_holder
       self.__balance = initial_balance  # Private attribute

   def deposit(self, amount):
       if amount > 0:
           self.__balance += amount
           print(f"Deposited ${amount}. New balance: ${self.__balance}")
       else:
           print("Deposit amount must be positive.")

   def withdraw(self, amount):
       if 0 < amount <= self.__balance:
           self.__balance -= amount
           print(f"Withdrew ${amount}. New balance: ${self.__balance}")
       else:
           print("Insufficient funds or invalid amount.")

   def __update_balance(self, amount):  # Private method
       self.__balance += amount

   def transfer(self, amount, other_account):
       if 0 < amount <= self.__balance:
           self.withdraw(amount)
           other_account.__update_balance(amount)
           print(f"Transferred ${amount} to {other_account.account_holder}.")
       else:
           print("Insufficient funds or invalid amount.")

We maken eerst een BankAccountclass die al het gewenste gedrag en de functionaliteit omvat die nodig zijn voor een BankAccount-object.

De BankAccount-klasse heeft een privé-attribuut __balance en een privémethode __update_balance:

  • Privévariabele (__balance): Dit is een attribuut van de BankAccount-klasse dat het huidige rekeningsaldo opslaat. Het is als privé gemarkeerd door de naam te laten voorafgaan door twee underscores (__). Dit betekent dat het alleen bedoeld is om binnen de klasse zelf te worden benaderd. Het wordt bijvoorbeeld aangepast door de methoden deposit, withdraw en __update_balance. Externe toegang tot dit attribuut wordt niet aanbevolen.
  • Privémethode (__update_balance): Het doel van deze methode is het bijwerken van het rekeningsaldo. Ze wordt aangeroepen door de methode transfer om tijdens een overboeking het saldo van de ontvangende rekening bij te werken. Door hier een privémethode te gebruiken, kapsel je de logica voor het bijwerken van het saldo in, zodat dit alleen kan op gecontroleerde manieren die door de klasse zijn gedefinieerd.

Voel je vrij om een nieuw Python-bestand te maken, de bovenstaande en onderstaande code te kopiëren en te plakken, en uit te voeren om het zelf te zien.

# Using the Bank Account Solution
account1 = BankAccount("John Doe", 1000)
account2 = BankAccount("Jane Doe", 500)

account1.deposit(200)
account1.withdraw(100)
account1.transfer(300, account2)

Je ziet dan de onderstaande output:

Deposited $200. New balance: $1200
Withdrew $100. New balance: $1100
Withdrew $300. New balance: $800
Transferred $300 to Jane Doe.

Gefeliciteerd! Je hebt je BankAccount-oplossing gemaakt met een privémethode!

Op basis van de output zien we dat bij de gebruikelijke bankhandelingen zoals storten, opnemen en overboeken, het gebruikelijke logische gedrag van een bankrekening wordt gevolgd.

De __init__-methode: is dit een privémethode?

Je hebt waarschijnlijk de methode __init__ gezien in het BankAccount-voorbeeld. Omdat deze ook dubbele underscores gebruikt, vraag je je misschien af of dit ook een privémethode is.

De methode __init__ wordt niet beschouwd als een privémethode op dezelfde manier als methoden die voor privacy met dubbele underscores worden voorafgegaan.

In plaats daarvan is het een onderdeel van speciale methoden in Python, vaak “dunder”-methoden genoemd (afkorting van “double underscore”), die een specifieke rol in de taal hebben. Andere voorbeelden van zulke speciale methoden zijn __str__, __repr__ en __del__.

Laten we begrijpen hoe deze speciale methode in ons voorbeeld is gebruikt:

class BankAccount:
   def __init__(self, account_holder, initial_balance=0):
       self.account_holder = account_holder
       self.__balance = initial_balance

Zoals we zien, is de methode __init__ de constructor voor een klasse. Deze wordt automatisch aangeroepen wanneer een nieuw exemplaar van de klasse wordt gemaakt, en wordt gebruikt om de attributen van het object te initialiseren. Voor de klasse BankAccount wordt de methode __init__ gebruikt om de beginwaarden in te stellen voor de attributen account_holder en __balance.

Geavanceerde concepten: name mangling in Python

Eerder gaven we aan dat privémethoden in Python slechts een conventie zijn en dat de Python-taal, in tegenstelling tot andere programmeertalen, privacy niet strikt afdwingt.

Dat klopt: we zagen dat privémethoden direct konden worden benaderd bij gebruik van een enkele underscore, maar dat de toegang werd beperkt bij gebruik van een dubbele underscore.

Waarom? Vanwege een concept dat “name mangling” wordt genoemd in Python.

Wanneer je een attribuutnaam laat voorafgaan door dubbele underscores, wijzigt Python de naam automatisch door een enkele underscore en de klassenaam vóór de oorspronkelijke attribuutnaam toe te voegen.

Deze gewijzigde naam is hoe het attribuut intern binnen de klasse wordt opgeslagen. Het proces van het op deze manier wijzigen van de naam staat bekend als name mangling.

Name mangling is om twee redenen nuttig:

  • Voorkomen van naamconflicten: Bij overerving zou een attribuut met dezelfde naam in een subklasse conflicteren met dat in de superklasse. Name mangling helpt dit te voorkomen door ervoor te zorgen dat namen uniek zijn per klasse.
  • Een zekere mate van privacy: Hoewel Python geen echt private attributen heeft, maakt name mangling attributen minder toegankelijk van buiten de klasse, en biedt zo een zekere mate van privacy.

Laten we een voorbeeld bekijken om dit beter te begrijpen.

class MyClass:
   def __init__(self):
       self.__private_attribute = "I am private"

   def __private_method(self):
       print("This is a private method")

obj = MyClass()
print(obj.__private_attribute)  # This will raise an AttributeError

In dit voorbeeld zijn __private_attribute en __private_method onderhevig aan name mangling. Intern worden ze respectievelijk opgeslagen als _MyClass__private_attribute en _MyClass__private_method. Pogingen om ze met hun oorspronkelijke namen van buiten de klasse te benaderen, resulteren in een AttributeError.

Je kunt ze echter nog steeds benaderen met hun gemanglede namen:

print(obj._MyClass__private_attribute)  # This will print "I am private"
obj._MyClass__private_method()  # This will print "This is a private method"

Hoewel name mangling attributen minder toegankelijk maakt, is het belangrijk om te benadrukken dat dit geen waterdichte manier is om privacy in Python te garanderen. Het is vooral een conventie om aan te geven dat een attribuut is bedoeld voor intern gebruik binnen de klasse.

Best practices voor het gebruik van privémethoden en -variabelen

Privémethoden en -variabelen effectief inzetten vraagt om het volgen van bepaalde best practices. Deze zorgen ervoor dat je code niet alleen functioneel is, maar ook duidelijk, onderhoudbaar en veilig.

Hier zijn enkele best practices om te volgen:

  • Gebruik een enkele underscore voor “beschermde” attributen. Als je wilt aangeven dat een attribuut of methode bedoeld is voor gebruik binnen de klasse en zijn subklassen, maar niet voor extern gebruik, laat je deze voorafgaan door een enkele underscore (_). Dit is een conventie in Python die andere ontwikkelaars signaleert dat het attribuut of de methode “beschermd” is en niet direct moet worden benaderd.
  • Gebruik dubbele underscore voor “privé” attributen. Als je een attribuut of methode minder toegankelijk wilt maken van buiten de klasse om toevallige wijziging of gebruik te vermijden, laat je deze voorafgaan door een dubbele underscore (__). Dit triggert name mangling en maakt het lastiger (maar niet onmogelijk) om het attribuut of de methode van buiten de klasse te benaderen.
  • Gebruik privémethoden voor interne logica. Privémethoden (die met een enkele of dubbele underscore) zijn een goede manier om de interne logica van je klasse in te kapselen. Gebruik ze voor taken die specifiek zijn voor de implementatie van de klasse en niet moeten worden blootgesteld als onderdeel van de publieke interface.

Tot slot is het belangrijk om consistent te zijn met je codeerconventies. Houd je aan de naamgevingsconventies en gebruik ze consequent in je codebase. Dit maakt je code begrijpelijker en onderhoudbaarder voor andere ontwikkelaars én voor je toekomstige zelf.

Conclusie

In deze tutorial heb je kennisgemaakt met de concepten achter privémethoden, hun syntaxis en wanneer je ze kunt gebruiken. We hebben ook meerdere voorbeelden gezien die illustreren hoe je ze in je volgende codeerproject kunt toepassen. Tot slot hebben we enkele best practices bekeken om in gedachten te houden bij het gebruik ervan.

Voor verdere verdieping kun je de Python Programming Skill Track en de cursus Object-oriented Programming in Python bekijken.

Arunn Thevapalan

Auteur

Arunn Thevapalan

Als senior data scientist ontwerp, ontwikkel en implementeer ik grootschalige machinelearningsoplossingen om bedrijven te helpen betere, datagedreven beslissingen te nemen. Als schrijver over data science deel ik inzichten, carrièreadvies en diepgaande, praktijkgerichte tutorials.

Onderwerpen

Gerelateerd