ホームページ  >  記事  >  バックエンド開発  >  Python でのメタクラスとその使用法の詳細な説明

Python でのメタクラスとその使用法の詳細な説明

巴扎黑
巴扎黑オリジナル
2017-07-20 09:30:331506ブラウズ

1. メタクラスを使用してサブクラスを検証します

新しいクラスを定義するたびに、メタクラスは 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())

2、用元类注册子类

每次从基类中继承子类时,基类的元类都可以自动运行注册代码。
这在需要反向查找 ‘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)

3、用元类注解类的属性

使用元类像是在 class 语句上放置了挂钩,class语句处理完毕,挂钩就会立刻触发。
下列中借助元类设置了 Filed.nameFiled.nameこれにより、このクラスの __init__ メソッドに検証コードを配置し、オブジェクトが構築されるまで待ってから検証する必要がなくなります。


次の例では、エッジが 3 つ未満のサブクラスが定義されており、クラス ステートメントが終了するとすぐに、メタクラス検証コードによってクラスが拒否されます。

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

2. サブクラスをメタクラスに登録する

基本クラスからサブクラスを継承するたびに、基本クラスのメタクラスが登録コードを自動的に実行できます。

これは、単純な識別子と対応するクラスの間のマッピングを確立するために「逆引き参照」が必要な場合に便利です。 🎜依然として使用されているのは、クラス ステートメントが実行された後、メタクラスの __new__ メソッドが自動的に呼び出されるということです。 🎜rrreee🎜3. メタクラスを使用してクラス属性に注釈を付ける🎜🎜 メタクラスの使用は、クラス ステートメントが処理された後、すぐにフックがトリガーされるようになります。 🎜以下では、Filed.nameFiled.name はメタクラスを利用して設定されています。 🎜rrreee🎜🎜これはメタクラスの概要ですが、私は完全に理解していません。 🎜このことを深く理解している Python 愛好家がメッセージを残していただければ幸いです。 🎜🎜コードのソース: 🎜

以上がPython でのメタクラスとその使用法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。