À quoi servent les métaclasses Python?
8 réponses
Metaclasses sont indispensables si vous voulez avoir des objets de classe (par opposition à instances d'objets de classe) équipés de "comportement spécial personnalisé", puisque le comportement d'un objet dépend de méthodes spéciales sur le type de l'objet, et le type d'un objet de classe est, exactement un synonyme pour, le metaclass.
par exemple, si vous voulez un objet de classe X tel que " print X "emits" le temps est maintenant 8: 46am" (à 8: 46AM) am, ou, plus généralement, l'heure actuelle) cela doit signifier que type(x)
(alias metaclass de X) a une coutume spéciale __str__
méthode -- et de même (avec les diverses méthodes spéciales applicables) si vous voulez donner un sens à des expressions telles que X + Y
où X et Y sont à la fois des objets de classe, ou X[23]
(où X, encore une fois, est un objet de classe), et ainsi de suite.
la plupart des autres tâches de personnalisation sont maintenant (en python 2.6 ou mieux) plus faciles à implémenter avec une classe décorateur, qui peut modifier un objet de classe immédiatement après la fin de la déclaration class
. Il y a quelques autres cas où cela n'est pas faisable parce que les modifications doivent être faites très tôt si elles doivent avoir un effet quelconque (par exemple, le réglage ou la modification de __slots__
).
en Python 3, les métaclasses gagnent un petit peu d'utilité supplémentaire: une métaclasse peut désormais spécifier en option l'objet de mapping à peupler lors de l'exécution de la déclaration class
corps (par défaut, c'est normal dict
). Cela permet de conserver et d'utiliser l'ordre des fixations de noms dans le corps de classe (alors que la normale dict
perd de l'ordre), ce qui est parfois agréable quand la classe doit avoir des "champs" dans un certain ordre spécifique (par exemple pour mapper 1:1 sur un C struct
, une ligne dans un fichier CSV ou une table DB, et similaire) -- en Python 2.* cela a dû être spécifié de façon redondante (généralement avec un attribut de classe supplémentaire qui est une séquence et ainsi, préserve l'ordre), et cette fonctionnalité de metaclasses Python 3 permet de supprimer la redondance.
ajoutez plus de flexibilité à votre programmation:
mais selon ce Metaclass programmation en Python vous pourriez ne pas avoir besoin d'eux (encore )
les métaclasses sont une magie plus profonde que 99% des utilisateurs ne devraient jamais s'inquiéter. Si vous vous demandez si vous en avez besoin, vous n'en avez pas besoin (les gens qui en ont besoin savent avec certitude qu'ils en ont besoin, et n'ont pas besoin d'une explication à ce sujet).
-- Python Guru Tim Peters
j'utilise des métaclasses avec une certaine fréquence, et c'est un outil extrêmement puissant à avoir dans la boîte à outils. Parfois, votre solution à un problème peut être plus élégant, moins de code, avec que sans.
ce que je me retrouve à utiliser des métaclasses le plus souvent, c'est le post-traitement des attributs de classe lors de la création de classe. Par exemple, définir un attribut name
sur les objets le cas échéant (comme le fonctionnement de L'ORM Django):
class AutonamingType(type):
def __init__(cls, name, bases, attrs):
for k,v in attrs.iteritems():
if getattr(v, '__autoname__', False):
v.name = k
class Autonamer(object):
__metaclass__ = AutonamingType
si vous avez ceci comme un outil, et vous utilisez une classe qui doit connaître son name
avant qu'elle ne puisse do_something()
:
class Foo(object):
__autoname__ = True
def __init__(self, name=None):
self.name = name
def do_something(self):
if self.name is None:
raise ValueError('name is None')
# now, do something
Il peut faire la différence dans le reste de votre code entre ceci:
class Bar(object):
myfoo1 = Foo('myfoo1')
myfoo2 = Foo('myfoo2')
myfoo3 = Foo('myfoo3')
et ceci:
class Baaz(Autonamer):
myfoo1 = Foo()
myfoo2 = Foo()
myfoo3 = Foo()
réduisant ainsi la duplication (et les chances que le nom de la variable et le nom assigné ne soient pas synchronisés).
si vous cherchez des exemples d'utilisation du mécanisme metaclass, vous pouvez lire le code source de django.les formes .
le style déclaratif de la définition de la forme est mis en œuvre au moyen de metaclass.
ils sont rarement nécessaires, mais sont utiles dans les endroits où vous voulez ajouter un comportement au comportement de base d'un objet -- comparer la programmation orientée vers L'Aspect, ou l'instrumentation faite dans des cadres de persistance comme Hibernate.
par exemple, vous pouvez vouloir une classe qui persiste ou enregistre chaque nouvel objet.
probablement il n'y a rien qui puisse être fait exclusivement avec des métaclasses, mais pour certaines personnes (dont la mienne) c'est un outil intéressant que vous pouvez utiliser. Il suffit de faire attention à ne pas abuser, car il peut être délicat.
Par exemple, j'ai utilisé la métaprogrammation dans un projet récent. C'était une feuille de calc OpenOffice, qui, en utilisant des macros pyUNO, génère des fichiers avec des informations. Il y a une fiche qui présente à l'utilisateur les informations à remplir, et les autres peuvent être utilisés pour décrire le genre d'éléments et leurs propriétés. L'utilisateur peut alors sélectionner le nombre d'éléments et le type de chacun, et générer les fichiers. La macro va créer une classe via métaprogrammation suivant la configuration sur chaque feuille. Ensuite, l'utilisateur peut instancier chaque classe et de générer des objets.
cela pouvait se faire sans métaprogrammation, mais il me semblait naturel d'utiliser les capacités de métaprogrammation pour le faire.
regardez les sources de Django - par exemple les métaclasses sont utilisées pour générer des modèles.
http://code.djangoproject.com/wiki/DynamicModels
sur le plan interne, Django utilise des métaclasses pour créer des modèles basés sur une classe que vous dans votre code source. Sans entrer dans trop de détails, que signifie que, plutôt que de vos classes étant les vrais modèles, Django reçoit un description de votre classe, qu'il utilise pour créer un modèle dans son lieu.
le premier commentateur déclare que l'utilisation des métaclasses ici était" une pierre précieuse "qui l'a aidé à traquer les erreurs inattendues qui avaient eu lieu pendant (beaucoup) "jours".