Les métaclasses en python

Quand l'interpréteur python rencontre une classe il crée un nouvel espace de nom et exécute tout le contenu de la classe dans cet espace, une classe peut contenir des attributs, des méthodes et biensûr d'autres classes. à la différence d'autres langages presque n'importe quelle instruction est possible à l'intérieur d'une classe même un "print".

>>> class Test():
... print "Début ..."
... attribut = "attr1"
... print "Fin"
...
Début ...
Fin

En arrière plan l'interpréteur appelle l'objet "type" qui se charge de créer la classe en question, ceci se fait automatiquement dès que l'analyse du contenu de la classe est terminée.

Le constructeur de "type" accepte 3 paramètres:

Comme n'importe qu'elle autre objet python on peut instancier l'objet type. ceci veut dire qu'on pourra créer des classes dynamiquement, exemple:

>>> prenom = "Amine"
>>> nom = "CHOUKI"
>>> def nom_complet(self):
... return "%s %s" % (self.prenom, self.nom)
...
>>> Personne = type("Personne", (object,), {"nom":nom, "prenom":prenom, "nom_complet":nom_complet})
NameError: name 'Personne' is not defined
>>> instance = Personne()
>>> instance.nom
'CHOUKI'
>>> instance.prenom
'Amine'
>>> instance.nom_complet()
'Amine CHOUKI'

Ceci peut être très utile si on ne connaît pas d'avance les classes de notre programme.

L'objet type est en fait une métaclasse, en d'autres termes une classes qui crée d'autres classes. quand on précise pas l'attribut "metaclass" dans une classe python l'objet type est affecté par default, ceci veut dire qu'on peut créer notre propre metaclasse ou hériter de type pour ajouter un comportement, des attributs ...

exemple basique:

>>> class MetaDescription(type):
... def __init__(cls, name, bases, attrs):
... print "Nom de la classe: %s" % name
... print "Attributs :"
... for name in attrs:
... print "%s: %r" % (name, attrs[name])
...
>>> class Test(object):
... __metaclass__ = MetaDescription
... autre = "Simple attribut"
...
Nom de la classe: Test
Attributs :
autre: 'Simple attribut'
__module__: '__main__'
__metaclass__: <class '__main__.MetaDescription'>
>>>

Pour montrer l'utilité d'une métaclasse j'ai choisi un petit exemple (inspiré du code de Django) qui permet de lister les classes filles d'une classe.

>>> class BaseModel(type):
... def __init__(cls, name, bases, attrs):
... try:
... if Model not in bases:
... return
... except:
... return
... Model._subclasses.append(cls)
...
>>> class Model(object):
... __metaclass__ = BaseModel
... _subclasses = []
...
>>> class Personne(Model):
... print "peut importe"
...
peut importe
>>> class Voiture(Model):
... print "peut importe"
...
peut importe
>>> Model._subclasses
[<class '__main__.Personne'>, <class '__main__.Voiture'>]

Bon développement ;).

Commentaires (1):

Par Merwin
Merci pour cet article, je ne savais pas ce qu'était les méta classes :-)

Ajouter un commentaire

Nom :*
Email :*
Site perso :
Commentaire :*
chargement