新しいクラスを定義するたびに、メタクラスは Yazheng コードを実行して、新しいクラスが指定された仕様を満たしていることを確認します。
Python システムは、サブクラスのクラス ステートメントの処理を完了した後、メタクラスの __new__
メソッドを呼び出します。メタクラスは、__new__
メソッドを通じて、サブクラスと孫クラスの名前、親、属性を取得できます。 __new__
方法。元类可以通过 __new__
方法,获取子类、孙子类的名称,父亲及属性。
这样使得我们不需要将验证代码放在本类 __init__
方法中,等到构建对象再验证。
下例中,定义一个边数小于3的子类,class语句一结束,元类的验证代码就会拒绝这个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())
每次从基类中继承子类时,基类的元类都可以自动运行注册代码。
这在需要反向查找 ‘reverse lookup’ 时很有用,使得在简单标识符和对应的类之间,建立映射关系。
依然利用的是class语句执行完,自动调用元类的 __new__
方法。
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)
使用元类像是在 class 语句上放置了挂钩,class语句处理完毕,挂钩就会立刻触发。
下列中借助元类设置了 Filed.name
和 Filed.name
これにより、このクラスの __init__
メソッドに検証コードを配置し、オブジェクトが構築されるまで待ってから検証する必要がなくなります。
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__)
基本クラスからサブクラスを継承するたびに、基本クラスのメタクラスが登録コードを自動的に実行できます。
これは、単純な識別子と対応するクラスの間のマッピングを確立するために「逆引き参照」が必要な場合に便利です。 🎜依然として使用されているのは、クラス ステートメントが実行された後、メタクラスの__new__
メソッドが自動的に呼び出されるということです。 🎜rrreee🎜3. メタクラスを使用してクラス属性に注釈を付ける🎜🎜 メタクラスの使用は、クラス ステートメントが処理された後、すぐにフックがトリガーされるようになります。 🎜以下では、Filed.name
と Filed.name
はメタクラスを利用して設定されています。 🎜rrreee🎜🎜これはメタクラスの概要ですが、私は完全に理解していません。 🎜このことを深く理解している Python 愛好家がメッセージを残していただければ幸いです。 🎜🎜コードのソース: 🎜以上がPython でのメタクラスとその使用法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。