Maison > Article > développement back-end > Explication détaillée des métaclasses et de leur utilisation en Python
Chaque fois que nous définissons une nouvelle classe, la métaclasse exécutera le code Yazheng pour garantir que la nouvelle classe est conforme aux spécifications spécifiées.
Une fois que le système Python aura traité l'instruction de classe de la sous-classe, il appellera la méthode __new__
de la métaclasse. La métaclasse peut obtenir le nom, le parent et les attributs de la sous-classe et de la classe petit-enfant via la méthode __new__
.
Cela nous évite d'avoir à mettre le code de vérification dans la méthode __init__
de cette classe et d'attendre que l'objet soit construit avant de vérifier.
Dans l'exemple suivant, une sous-classe avec moins de 3 arêtes est définie. Une fois l'instruction de classe terminée, le code de vérification de la métaclasse rejettera la classe.
class ValidatePolygon(type): def __new__(meta, name, bases, class_dict): # Don't validate the abstract Polygon class if bases != (object,): if class_dict['sides'] < 3: raise ValueError('Polygons need 3+ sides') return type.__new__(meta, name, bases, class_dict) class Polygon(object, metaclass=ValidatePolygon): sides = None # Specified by subclasses @classmethod def interior_angles(cls): return (cls.sides - 2) * 180 class Triangle(Polygon): sides = 3 print(Triangle.interior_angles())
Chaque fois que vous héritez d'une sous-classe d'une classe de base, la métaclasse de la classe de base peut exécuter automatiquement le code d'enregistrement.
Ceci est utile lorsqu'une « recherche inversée » est nécessaire pour établir un mappage entre un identifiant simple et la classe correspondante.
Ce qui est toujours utilisé, c'est qu'après l'exécution de l'instruction de classe, la méthode __new__
de la métaclasse est automatiquement appelée.
import json registry = {} def register_class(target_class): registry[target_class.__name__] = target_class def deserialize(data): params = json.loads(data) name = params['class'] target_class = registry[name] return target_class(*params['args']) class Meta(type): def __new__(meta, name, bases, class_dict): cls = type.__new__(meta, name, bases, class_dict) register_class(cls) return cls class Serializable(object): def __init__(self, *args): self.args = args def serialize(self): return json.dumps({ 'class': self.__class__.__name__, 'args': self.args, }) def __repr__(self): return '%s(%s)' % ( self.__class__.__name__, ', '.join(str(x) for x in self.args)) class RegisteredSerializable(Serializable, metaclass=Meta): pass class Vector3D(RegisteredSerializable): def __init__(self, x, y, z): super().__init__(x, y, z) self.x, self.y, self.z = x, y, z v3 = Vector3D(10, -7, 3) print('Before: ', v3) data = v3.serialize() print('Serialized:', data) print('After: ', deserialize(data)) print(registry)
Utiliser des métaclasses, c'est comme placer un hook sur l'instruction de classe. Une fois l'instruction de classe traitée, le hook sera déclenché immédiatement.
Les ensembles suivants Filed.name
et Filed.name
à l'aide de métaclasses.
class Field(object): def __init__(self): # These will be assigned by the metaclass. self.name = None self.internal_name = None def __get__(self, instance, instance_type): if instance is None: return self return getattr(instance, self.internal_name, '') def __set__(self, instance, value): setattr(instance, self.internal_name, value) class Meta(type): def __new__(meta, name, bases, class_dict): for key, value in class_dict.items(): if isinstance(value, Field): value.name = key value.internal_name = '_' + key cls = type.__new__(meta, name, bases, class_dict) return cls class DatabaseRow(object, metaclass=Meta): pass class BetterCustomer(DatabaseRow): first_name = Field() last_name = Field() prefix = Field() suffix = Field() foo = BetterCustomer() print('Before:', repr(foo.first_name), foo.__dict__) foo.first_name = 'Euler' print('After: ', repr(foo.first_name), foo.__dict__)
Ceci est le résumé de la métaclasse, et je ne le comprends pas complètement.
J'espère que les pythoneurs qui ont une profonde compréhension de cela pourront laisser un message.
Code de :
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!