Home >Backend Development >Python Tutorial >Detailed explanation of metaclasses and their usage in Python
Whenever we define a new class, the metaclass will run Yazheng code to ensure that the new class conforms to the specified specifications.
After the Python system has processed the class statement of the subclass, it will call the __new__
method of the metaclass. The metaclass can obtain the name, parent and attributes of the subclass and grandchild class through the __new__
method.
This eliminates the need for us to put the verification code in the __init__
method of this class and wait until the object is built before verifying.
In the following example, a subclass with less than 3 edges is defined. Once the class statement ends, the metaclass verification code will reject the class.
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())
Every time you inherit a subclass from a base class, the metaclass of the base class can automatically run the registration code.
This is useful when a 'reverse lookup' is required to establish a mapping between a simple identifier and the corresponding class.
Still used is that after the class statement is executed, the __new__
method of the metaclass is automatically called.
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)
Using metaclasses is like placing a hook on the class statement. After the class statement is processed, the hook will be triggered immediately.
In the following, Filed.name
and Filed.name
are set with the help of metaclasses.
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__)
The metaclass summary ends here, and I don’t fully understand it.
I hope pythoners who have a deep understanding of this can leave a message.
Code comes from:
The above is the detailed content of Detailed explanation of metaclasses and their usage in Python. For more information, please follow other related articles on the PHP Chinese website!