Python >> Tutoriel Python >  >> Python

Métaclasses Python

Résumé :les métaclasses sont une classe d'une classe . En d'autres termes, une classe est une instance d'une métaclasse . La métaclasse peut être créée à l'aide de deux méthodes :(1)type Classe qui est la métaclasse intégrée dans Python. (2) Créer une métaclasse personnalisée en utilisant le metaclass mot-clé.

Problème : Que sont les métaclasses et pourquoi les utilisons-nous en Python ?

Avant de plonger dans les métaclasses, il est fortement recommandé de parcourir les concepts de classes et d'objets. Nous avons ici un tutoriel et un cours complet qui vous aide à comprendre les concepts de programmation orientée objet en python. Vous voudrez peut-être jeter un œil au cours sur ce lien. Cela dit, révisons rapidement l'orientation objet de Python.

Veuillez balayer l'écran vers la droite pour parcourir les concepts de notre publication Instagram :

https://www.instagram.com/p/B4abtbzoq4H/?utm_source=ig_embed

Honnêtement, les métaclasses sont un concept avancé en Python et peuvent être assez complexes à appréhender. Cependant, dans cet article, je vais essayer de vous simplifier la tâche.

Qu'est-ce qu'une métaclasse ? ?

Le terme méta signifie quelque chose qui est autoréférentiel. Vous auriez probablement entendu parler de métadonnées, c'est-à-dire de données sur des données. (S'il vous plaît ne vous inquiétez pas si vous ne l'avez pas!). Par conséquent, Meta-X signifierait généralement le X sur le X. J'espère que vous comprenez. Cela nous amène finalement à la question :Qu'est-ce qu'une "métaclasse" ?

Comme nous savons qu'un objet est une instance d'une classe, de même une classe est une instance d'une métaclasse. Par conséquent, il est prudent de dire que la métaclasse est une classe de classe. En termes simples, tout comme les classes qui déterminent le comportement des objets, les métaclasses déterminer le comportement d'une classe. Par conséquent, les métaclasses fournissent du code pour la création et l'exécution de classes. Pour simplifier davantage, examinons l'analogie ci-dessous :

Instances :Classes ::Classes :Instances

Un exemple concret pour vous qui devrait s'expliquer de lui-même :

Avant de poursuivre notre discussion, voici une règle empirique en Python que je souhaite vous rappeler :

Tout en Python est un objet.

Le type Métaclasse

Pour saisir le concept de métaclasses, il est extrêmement important de comprendre l'utilisation du type en Python.

En termes simples, type est une métaclasse qui produit d'autres classes.

Il existe maintenant 3 façons différentes d'utiliser type en Python :

  1. type peut être utilisé pour trouver le type d'un Objet.
  2. type peut être utilisé pour trouver le type d'un Classe.
  3. type peut être utilisé pour Créer de nouvelles classes .

Plongeons maintenant dans chaque cas d'utilisation du type métaclasse à l'aide d'exemples.

Utiliser taper pour trouver le type d'un objet

Comme indiqué ci-dessus dans la règle du pouce, tout en python est un objet. Cela signifie que peu importe que vous utilisiez une variable de chaîne, un dictionnaire ou un tuple, tous sont traités comme des objets en Python.

Examinons le programme suivant qui renvoie le type d'une variable chaîne et un objet d'une classe. (Veuillez suivre les commentaires dans le code ci-dessous pour une meilleure compréhension du concept.)

#creating a class
class Finxter(object):
  pass

#instatiating the class with an object
obj = Finxter()
# finding the type of the object
print(type(obj)) 

# creating a string variable
name = 'Harry'
# finding the type of the variable name
print(type(name))

Sortie :

Utiliser taper Pour trouver le type de Classe

Revenons à nouveau à notre règle de base où nous avons étudié que tout en Python est une classe. Cela signifie que la classe est également un objet en Python et doit avoir un type comme tout autre objet. Découvrons quel est le type d'une classe en python dans le programme suivant :

#creating a class
class Finxter(object):
  pass

#instatiating the class with an object
obj = Finxter()
# finding the type of class Finxter
print(type(Finxter)) 
# finding type of class string <str>
print(type(str))

Sortie :

<class 'type'>
<class 'type'>

La sortie ci-dessus montre clairement que type est la métaclasse de toutes les classes en Python.

TRIVIA : type est sa propre métaclasse. Pour comprendre ce que cela signifie, examinons la ligne de code ci-dessous :

print(type(type))

Sortie :

<class 'type'>

Utiliser taper Pour créer une nouvelle classe

Lorsque le type la classe est appelée avec un seul argument, elle renvoie le type d'objet mais lorsqu'elle est appelée en utilisant 3 paramètres , il crée une classe.

Les arguments suivants donnés ci-dessous sont passés au type classe :

  1. Nom de la classe.
  2. Tuple contenant les classes de base héritées par la classe.
  3. Un dictionnaire de classes qui sert d'espace de noms local et contient des méthodes et des variables de classe.

★ La syntaxe pour créer une classe en utilisant le type la classe a été donnée ci-dessous :

Exemple 1 : Un exemple simple qui n'a pas de classe héritée et un dictionnaire de classe vide.

Finxter = type('Finxter', (), {})
obj = Finxter()
print(obj)

Sortie :

<__main__.Finxter object at 0x7f8cf58025e0>

Exemple 2 : Examinons maintenant un programme qui contient le nom de la classe, une classe de base et un attribut dans le dictionnaire.

def coffee(self): 
	print("Factory Class - Coffee Class Method!") 

# base class 
class machine: 
	def vendingMachine(self): 
		print("Base Class - Machine Class Method!") 

# creating factory class 
factory = type('factory', (machine, ), dict(greet="Welcome Finxter!", foo=coffee)) 
# Creating instance of factory class 
obj = factory() 
# calling inherited method 
obj.vendingMachine() 
# calling factory class method 
obj.foo()
# printing variable 
print(obj.greet) 

Sortie :

Base Class - Machine Class Method!
Factory Class - Coffee Class Method!
Welcome Finxter!

Exemple 3 : Un exemple complexe qui a une fonction externe qui est assignée à l'attribut du dictionnaire d'espace de noms en utilisant le nom de la fonction.

# Defining external function
def foo(object):
  print("value = ",object.val)

# Creating class using type with attributes val and code that access the external function 
Finxter = type('Finxter', (), {'val':'PYTHON','code':foo})

# Using Object of Finxter class to access the attributes
obj = Finxter()
print(obj.val)
obj.code()

Sortie :

PYTHON
value =  PYTHON

Maintenant, regardons la version simplifiée de la création du Finxter ci-dessus classe sans utiliser le type() fonction.

def foo(object):
  print("value = ",object.val)
 
class Finxter:
   val = "PYTHON"
   code = foo

obj = Finxter()
print(obj.val)
obj.code()

type est la métaclasse de données par défaut, mais elle contient des méthodes spéciales / "méthodes magiques" qui peuvent être utilisées pour créer des métaclasses personnalisées. Ces méthodes sont :

  • __new__()
  • __init__()
  • __prepare__()
  • __call__()

Création d'une métaclasse personnalisée

Que se passe-t-il lorsque nous créons une classe comme celle ci-dessous ?

class Finxter:
  pass

obj = Finxter()

Dès que l'objet pour la classe Finxter est créé le __call__() méthode de la métaclasse de type (qui se trouve être la classe parente de Finxter ) est invoqué. Le __call__() la méthode invoque alors le __new__() et __init__() méthodes. Comme ces méthodes ne sont pas définies dans la classe Finxter , ces méthodes sont automatiquement héritées. Cependant, nous pouvons remplacer ces méthodes dans une métaclasse personnalisée, fournissant ainsi un comportement personnalisé lors de l'instanciation de la classe Finxter .

Exemple : Considérons que nous avons un cadre de test et que nous voulons garder une trace de l'ordre dans lequel les classes sont définies. Nous pouvons le faire en utilisant une métaclasse. Voyons comment cela peut être fait dans le code suivant :

class MyMeta(type):

    counter = 0

    def __init__(cls, name, bases, d):
        type.__init__(cls, name, bases, d)
        cls._order = MyMeta.counter
        MyMeta.counter += 1
        print(cls._order," ",name)

class MyClass(metaclass=MyMeta):    
    pass

class MyClass_A(MyClass):
    pass

class MyClass_B(MyClass):    
    pass
    
class MyClass_C(MyClass):
    pass

Sortie :

0   MyClass
1   MyClass_A
2   MyClass_B
3   MyClass_C

Toute la sous-classe de MyClass obtient un attribut de classe _order qui enregistre l'ordre dans lequel les classes ont été définies.

Faut-il utiliser Metclasses ?

La réponse simple à cela est que si le problème peut être résolu par une méthode plus simple, vous ne devez pas utiliser de métaclasses car elles sont assez compliquées et difficiles à saisir. La plupart des modifications de classe peuvent être effectuées en utilisant d'autres techniques, comme l'utilisation de décorateurs de classe. Le principal cas d'utilisation de la métaclasse est la création d'une API, par exemple. Django ORM.

Python Guru Tim Peters (auteur du Zen Of Python) a dit :

Jetons un coup d'œil au programme suivant qui justifie davantage pourquoi nous devrions éviter l'utilisation de métaclasses à moins que cela ne soit absolument nécessaire. Nous utiliserons le même scénario que dans le cas précédent lors de la création d'une métaclasse personnalisée. Cependant, au lieu d'utiliser des métaclasses, nous utiliserons des décorateurs qui sont plus simples que la création de métaclasses personnalisées. Jetons un coup d'œil.

counter = 0

def decorator(cls):
  class Main(cls):
    global counter
    cls._order = counter
    print(cls._order," ",cls.__name__)
    counter += 1
  return Main

@decorator
class MyClass():    
    pass

@decorator
class MyClass_A(MyClass):
    pass

@decorator
class MyClass_B(MyClass):    
    pass

@decorator    
class MyClass_C(MyClass):
    pass

Sortie :

0   MyClass
1   MyClass_A
2   MyClass_B
3   MyClass_C

Si vous souhaitez en savoir plus sur les décorateurs, veuillez consulter notre tutoriel de blog ici.

Conclusion

Nous avons appris ce qui suit dans ce didacticiel :

  • Un récapitulatif rapide des concepts orientés objet en Python.
  • Qu'est-ce qu'une métaclasse ?
  • La métaclasse de type.
    • Utiliser le type pour trouver le type d'un objet.
    • Utiliser le type pour trouver le type de classe.
    • Utiliser le type pour créer une nouvelle classe.
  • Création d'une métaclasse personnalisée.
  • Pourquoi devrions-nous éviter d'utiliser des métaclasses ?

J'espère que vous avez appris les bases des métaclasses dans cet article. Veuillez vous abonner et rester à l'écoute pour d'autres articles intéressants !