ゆくゆくは有へと

おかゆ/彼ノ∅有生 の雑記

メタクラスで@propertyを使ってクラスプロパティをつくる

クラスプロパティってできんのかな~と思って調べていた。

fakatatuku.hatenablog.com

なるほどな~と思いつつ、この記事を読み返していた。

postd.cc

プロパティって(というかディスクリプタって)、インスタンスの生成元クラスのアトリビュートとして登録しておいて使うわけだから、クラスプロパティはクラスの生成元クラスにプロパティとして登録すればいいのでは?そんで、クラスの生成元クラスというのはつまりメタクラスでは?

というわけで、typeメタクラスのサブクラスにプロパティを登録して、それをメタクラスとしたクラスを作れば、その子は登録したプロパティが使えるはずや!

読み込み専用のクラスプロパティを作ってみまふ。

class PropertyXMeta(type):

    @property
    def x(self):
        return 0

    @x.setter
    def x(self, value):
        raise AttributeError


class Klass(metaclass=PropertyXMeta):
    pass

if __name__ == '__main__':
    print(Klass.x)
    try:
        Klass.x = 5
    except AttributeError:
        print("uh-huh, nice error.")

結果。

0
uh-huh, nice error.

Klass.x に代入しようとするとAttributeErrorが出るようになります。ガチもんの定数になりますね!(そこまでして変更不能にしたいかどうかはともかく)

上で見たような、@ClassPropertyといったデコレータをクラス内部に書いて使えるようにしたもののほうが実用的だとは思います。

クラスがメタクラスインスタンスだってことを改めて知れた実装でした。