Maison  >  Article  >  développement back-end  >  Explication détaillée des métaclasses et de leur utilisation en Python

Explication détaillée des métaclasses et de leur utilisation en Python

巴扎黑
巴扎黑original
2017-07-20 09:30:331550parcourir

1. Utilisez la métaclasse pour vérifier les sous-classes

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())

2. Enregistrez des sous-classes avec des métaclasses

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)

3. Utilisez des métaclasses pour annoter les attributs de classe

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn