6618 votes

Que sont les métaclasses en Python ?

En Python, que sont les métaclasses et à quoi servent-elles ?

25voto

Gigantic Points 4447

En plus des réponses publiées, je peux dire qu'un metaclass définit le comportement d'une classe. Ainsi, vous pouvez définir explicitement votre métaclasse. Chaque fois que Python reçoit un mot-clé class puis il commence à chercher le metaclass . S'il n'est pas trouvé, le type de métaclasse par défaut est utilisé pour créer l'objet de la classe. En utilisant le __metaclass__ vous pouvez définir l'attribut metaclass de votre classe :

class MyClass:
   __metaclass__ = type
   # write here other method
   # write here one more method

print(MyClass.__metaclass__)

Le résultat sera le suivant :

class 'type'

Et, bien sûr, vous pouvez créer votre propre metaclass pour définir le comportement de toutes les classes qui sont créées en utilisant votre classe.

Pour ce faire, il faut utiliser la méthode par défaut metaclass doit être héritée car il s'agit de la principale classe de type metaclass :

class MyMetaClass(type):
   __metaclass__ = type
   # you can write here any behaviour you want

class MyTestClass:
   __metaclass__ = MyMetaClass

Obj = MyTestClass()
print(Obj.__metaclass__)
print(MyMetaClass.__metaclass__)

La sortie sera :

class '__main__.MyMetaClass'
class 'type'

16voto

Lars Points 73

Notez que dans python 3.6 une nouvelle méthode dunder __init_subclass__(cls, **kwargs) a été introduit pour remplacer un grand nombre de cas d'utilisation courante des métaclasses. Est appelé lorsqu'une sous-classe de la classe de définition est créée. Voir documentation python .

14voto

VenuGopalTewari Points 144

En programmation orientée objet, une métaclasse est une classe dont les instances sont des classes. Tout comme une classe ordinaire définit le comportement de certains objets, une métaclasse définit le comportement de certaines classes et de leurs instances. Le terme métaclasse signifie simplement quelque chose utilisé pour créer des classes. En d'autres termes, c'est la classe d'une classe. La métaclasse est utilisée pour créer la classe. Ainsi, tout comme l'objet est une instance d'une classe, une classe est une instance d'une métaclasse. En python, les classes sont également considérées comme des objets.

3 votes

Plutôt que de donner des définitions livresques, il aurait été préférable d'ajouter quelques exemples. La première ligne de votre réponse semble avoir été copiée de l'entrée Wikipedia de Metaclasses.

2 votes

@verisimilitude Je suis également en apprentissage pouvez-vous m'aider à améliorer cette réponse en apportant des exemples pratiques issus de votre expérience ?

1 votes

"En programmation orientée objet, une métaclasse est une classe dont les instances sont des classes. Tout comme une classe ordinaire définit le comportement de certains objets, une métaclasse définit le comportement de certaines classes et de leurs instances." Métaclasse - Wikipédia . Les 2 premières phrases, mot pour mot. En quoi cette réponse profite-t-elle à quelqu'un d'autre que votre score de réputation ? Votre spécialité n'est pas Python, les métaclasses sont parmi les concepts les plus complexes et les moins bien compris de Python et il ne manque pas d'excellentes réponses. Qu'est-ce qu'un copier-coller apporte à la table ?

14voto

Carson Arucard Points 334

Voici un autre exemple de ce à quoi il peut servir :

  • Vous pouvez utiliser le metaclass pour modifier la fonction de son instance (la classe).

    class MetaMemberControl(type): slots = ()

    @classmethod
    def __prepare__(mcs, f_cls_name, f_cls_parents,  # f_cls means: future class
                    meta_args=None, meta_options=None):  # meta_args and meta_options is not necessarily needed, just so you know.
        f_cls_attr = dict()
        if not "do something or if you want to define your cool stuff of dict...":
            return dict(make_your_special_dict=None)
        else:
            return f_cls_attr
    
    def __new__(mcs, f_cls_name, f_cls_parents, f_cls_attr,
                meta_args=None, meta_options=None):
    
        original_getattr = f_cls_attr.get('__getattribute__')
        original_setattr = f_cls_attr.get('__setattr__')
    
        def init_getattr(self, item):
            if not item.startswith('_'):  # you can set break points at here
                alias_name = '_' + item
                if alias_name in f_cls_attr['__slots__']:
                    item = alias_name
            if original_getattr is not None:
                return original_getattr(self, item)
            else:
                return super(eval(f_cls_name), self).__getattribute__(item)
    
        def init_setattr(self, key, value):
            if not key.startswith('_') and ('_' + key) in f_cls_attr['__slots__']:
                raise AttributeError(f"you can't modify private members:_{key}")
            if original_setattr is not None:
                original_setattr(self, key, value)
            else:
                super(eval(f_cls_name), self).__setattr__(key, value)
    
        f_cls_attr['__getattribute__'] = init_getattr
        f_cls_attr['__setattr__'] = init_setattr
    
        cls = super().__new__(mcs, f_cls_name, f_cls_parents, f_cls_attr)
        return cls

    class Human(metaclass=MetaMemberControl): slots = ('_age', '_name')

    def __init__(self, name, age):
        self._name = name
        self._age = age
    
    def __getattribute__(self, item):
        """
        is just for IDE recognize.
        """
        return super().__getattribute__(item)
    
    """ with MetaMemberControl then you don't have to write as following
    @property
    def name(self):
        return self._name
    
    @property
    def age(self):
        return self._age
    """

    def test_demo(): human = Human('Carson', 27)

    human.age = 18 # you can't modify private members:_age <-- this is defined by yourself.

    # human.k = 18  # 'Human' object has no attribute 'k'  <-- system error.
    age1 = human._age  # It's OK, although the IDE will show some warnings. (Access to a protected member _age of a class)
    
    age2 = human.age  # It's OK! see below:
    """
    if you do not define `__getattribute__` at the class of Human,
    the IDE will show you: Unresolved attribute reference 'age' for class 'Human'
    but it's ok on running since the MetaMemberControl will help you.
    """

    if name == 'main': test_demo()

Le site metaclass est puissant, il y a beaucoup de choses (comme la magie des singes) que vous pouvez faire avec lui, mais attention, cela peut n'être connu que de vous.

12voto

Swati Srivastava Points 831

Une classe, en Python, est un objet, et comme tout autre objet, elle est une instance de "quelque chose". Ce "quelque chose" est ce que l'on appelle une métaclasse. Cette métaclasse est un type spécial de classe qui crée les objets d'autres classes. La métaclasse est donc responsable de la création de nouvelles classes. Cela permet au programmeur de personnaliser la façon dont les classes sont générées.

Pour créer une métaclasse, la surcharge de l'option nouveau () et init () se fait généralement. nouveau () peut être surchargée pour changer la façon dont les objets sont créés, alors que init () peut être surchargée pour changer la façon d'initialiser l'objet. Les métaclasses peuvent être créées de plusieurs façons. L'une d'elles consiste à utiliser la fonction type(). La fonction type(), lorsqu'elle est appelée avec 3 paramètres, crée une métaclasse. Les paramètres sont :-

  1. Nom de la classe
  2. Tuple ayant des classes de base héritées par la classe
  3. Un dictionnaire contenant toutes les méthodes et les variables de la classe.

Une autre façon de créer une métaclasse consiste à utiliser le mot clé "metaclass". Définissez la métaclasse comme une simple classe. Dans les paramètres de la classe héritée, passez metaclass=metaclass_name.

La métaclasse peut être utilisée spécifiquement dans les situations suivantes :-.

  1. lorsqu'un effet particulier doit être appliqué à toutes les sous-classes
  2. Le changement automatique de classe (à la création) est requis
  3. Par les développeurs d'API

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X