Aangepaste metaklassen maken
In Python kunnen we het aanmaakproces van een klasse aanpassen door het trefwoord metaclass in de klassedefinitie mee te geven. Dit kan ook door te erven van een klasse waarin dit trefwoord al is meegegeven.
class MyMeta(type):
pass
class MyClass(metaclass=MyMeta):
pass
class MySubclass(MyClass):
pass
Hieronder zie je dat het type van de klasse MyMeta type is en dat het type van MyClass en MySubClass MyMeta is.
print(type(MyMeta))
print(type(MyClass))
print(type(MySubclass))
<class 'type'>
<class '__main__.MyMeta'>
<class '__main__.MyMeta'>
Als je een klasse definieert en er is geen metaklas gedefinieerd, wordt standaard de metaklas type gebruikt. Als een metaklas is opgegeven en deze is geen instantie van type(), dan wordt die direct als metaklas gebruikt.
__new__ en __init__
Metaklassen kunnen ook op een van de twee onderstaande manieren worden gedefinieerd. We leggen hieronder het verschil tussen beide uit.
class MetaOne(type):
def __new__(cls, name, bases, dict):
pass
class MetaTwo(type):
def __init__(self, name, bases, dict):
pass
__new__ wordt gebruikt wanneer je de dict of bases-tuple wilt definiëren voordat de klasse wordt aangemaakt. De retourwaarde van __new__ is meestal een instantie van cls. __new__ stelt subklassen van onveranderlijke typen in staat om het aanmaken van instanties aan te passen. Het kan in aangepaste metaklassen worden overschreven om de klassecreatie te beïnvloeden. __init__ wordt meestal aangeroepen nadat het object is aangemaakt om het te initialiseren.
Metaklasmethode __call__
Volgens de officiële documentatie kunnen we ook andere klassemethode overschrijven door een aangepaste __call__()-methode in de metaklas te definiëren, die aangepast gedrag mogelijk maakt wanneer de klasse wordt aangeroepen.
Metaklasmethode __prepare__
Volgens Python's data model-docs
Zodra de juiste metaklas is bepaald, wordt de klassenamespace voorbereid. Als de metaklas een attribuut __prepare__ heeft, wordt dit aangeroepen als namespace = metaclass.__prepare__(name, bases, **kwds) (waarbij de extra keyword-argumenten, indien aanwezig, uit de klassedefinitie komen). Als de metaklas geen attribuut __prepare__ heeft, dan wordt de klassenamespace geïnitialiseerd als een lege geordende mapping. - docs.python.org
Singleton-ontwerp met een metaklas
Dit is een ontwerppatroon dat het instantiëren van een klasse beperkt tot slechts één object. Dit kan bijvoorbeeld handig zijn bij het ontwerpen van een klasse die verbinding maakt met de database. Je wilt misschien slechts één instantie van de verbindingsklasse hebben.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonMeta,cls).__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonClass(metaclass=SingletonMeta):
pass
Conclusie
In dit artikel hebben we geleerd wat metaklassen zijn en hoe we ze kunnen toepassen in onze Python-programmering. Metaklassen kun je onder andere gebruiken voor logging, het registreren van klassen tijdens het aanmaken en voor profiling. Het lijken vrij abstracte concepten, en je vraagt je misschien af of je ze überhaupt nodig hebt. Doorgewinterde Pythonista Tim Peters beantwoordt die vraag het best.
"Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why).” - realpython
Wil je meer leren over Python? Start dan met DataCamp's Python Programming skill track en bekijk onze Python Classes Tutorial.

Een metaklas in Python is een klasse van een klasse die bepaalt hoe een klasse zich gedraagt. Een klasse is zelf een instantie van een metaklas. Een klasse in Python bepaalt hoe de instantie van die klasse zich zal gedragen. Om metaklassen goed te begrijpen, is het handig als je al ervaring hebt met Python-klassen. Voordat we dieper in metaklassen duiken, halen we eerst een paar begrippen uit de weg.
Alles in Python is een object
Python-klassen kunnen dynamisch worden aangemaakt
typein Python stelt ons in staat het type van een object te achterhalen. We kunnen het type controleren van het object dat we hierboven hebben gemaakt.Wacht, wat gebeurde hier? Je zou verwachten dat het type van het hierboven gemaakte object class is, maar dat is het niet. Houd die gedachte vast; we komen er zo op terug. We zien ook dat het type van
typezelftypeis. Het is een instantie vantype. Iets anders magisch dattypedoet, is dat het ons in staat stelt klassen dynamisch te maken. Hieronder laten we zien hoe we dat zouden doen. De klasseDataCamphieronder zou mettypeals volgt worden aangemaakt:In het bovenstaande voorbeeld is
DataCampde klassenaam, terwijlDataCampClassde variabele is die naar de klasse verwijst. Wanneer wetypegebruiken, kunnen we attributen van de klasse meegeven via een dictionary, zoals hieronder getoond:Als we willen dat onze
PythonClasserft van de klasseDataCamp, geven we die als tweede argument door bij het definiëren van de klasse mettypeNu die twee concepten uit de weg zijn, zien we dat Python klassen aanmaakt met behulp van een metaklas. We hebben gezien dat alles in Python een object is; deze objecten worden gemaakt door metaklassen. Wanneer we
classgebruiken om een klasse te maken, is er een metaklas die achter de schermen de klasse creëert. We hebbentypedit hierboven al in de praktijk zien doen. Het is vergelijkbaar metstrdat strings maakt enintdat gehele getallen maakt. In Python kun je met het attribuut___class__het type van de huidige instantie controleren. Laten we hieronder een string maken en het type controleren.We kunnen het type ook controleren met
type(article).Als we het type van
strcontroleren, blijkt ook dat het type is.Wanneer we het type controleren voor
float,int,list,tupleendict, krijgen we een vergelijkbare output. Dit komt omdat al deze objecten van het typetypezijn.We hebben al gezien dat
typeklassen creëert. Dus wanneer we de__class__van__class__controleren, zou dattypemoeten opleveren.