41
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pythonで考えるメタクラスとは?

Last updated at Posted at 2019-08-22

pythonで考えるメタクラスとは

メタクラスについて、pythonで初めて学んでみました。自分の備忘録も兼ねて、まとめてみたいと思います。

そもそもメタクラスって?

メタクラスって何でしょう、Wikipediaで調べてみると下記のように説明されています。

オブジェクト指向プログラミングにおいてメタクラスとは、インスタンスがクラスとなるクラスのことである。通常のクラスがそのインスタンスの振る舞いを定義するように、メタクラスはそのインスタンスであるクラスを、そして更にそのクラスのインスタンスの振る舞いを定義する。

(引用:https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%BF%E3%82%AF%E3%83%A9%E3%82%B9)

つまり、__クラスの振る舞いを定義するためのクラス__がメタクラスだと、なんとなくイメージできます。

ここでクラスの「振る舞い」を制御したいのなら、そのクラスの親クラスを作って、継承させるのと何が違うのでしょうか。それは制御したい「振る舞い」に違いがあると思っています。

親クラス(継承)とメタクラスの違い

親クラスの継承とメタクラスの役割について、私なりにざっくり整理すると以下のようになると思っています。

制御したい「振る舞い」 具体例
親クラス インスタンス__生成後__の挙動(どのように動くか) 複数の子クラスで同じ名前のメソッドを使いたい(ポリモーフィズムの実現)
メタクラス インスタンス__生成前(生成時)__の挙動(どのように定義されているか) クラス変数がすべて適切に定義されているかチェックしたい/直接関係しないクラス同士の中身も制御したい。

コード例

実際にコード例を見てみましょう。政令指定都市を定義するためのメタクラスを書いてみました。政令指定都市は人口が500万人以上の都市ですので、政令指定都市クラス定義時に人口が500万人以上かをチェックするようにします。

meta_sample.py

# 政令指定都市メタクラス
# メタクラスはtypeを継承する
class GovermentDesignatedMetaClass(type):
  def __new__(meta,name,bases,attributes):
    # __new__関数はクラス生成時に実行される関数
    # クラスの情報を受け取ることができる
    # name:クラス名, bases:親クラス, attributes:クラス属性
    if bases != (object,): #抽象クラスは検証しない
      if attributes["population"] < 5000000: # 500万人未満なら例外
        raise ValueError("This is not Goverment designated city")
    return type.__new__(meta,name,bases,attributes)


# 政令指定都市親クラス
# メタクラスの指定は「metaclass=...」で行う(Python3)
class GovermentDesignatedCity(object, metaclass=GovermentDesignatedMetaClass):
  population=None #子クラスで定義する

# 東京都 (政令指定都市)
class Tokyo(GovermentDesignatedCity):
  population = 10000000 #1千万人

# 松山市 (政令指定都市ではない)
class Matsuyama(GovermentDesignatedCity):
  population = 500000 #50万人

以上のようにメタクラスを定義し実行すると、Matsuyamaは人口が約50万人なので政令指定都市ではないため、下記のようにエラーメッセージが出力されます。

実行結果
Traceback (most recent call last):
  File "sample.py", line 15, in <module>
    class Matsuyama(GovermentDesignatedCity):
  File "sample.py", line 5, in __new__
    raise ValueError("This is not Goverment designated city")
ValueError: This is not Goverment designated city

メタクラスのメリット

お気づきかと思いますが、上記コードはMatsuyamaクラスを定義しただけで、どこにもインスタンスを生成していませんし、静的クラスとしても利用していません。これこそがメタクラスのメリットの一つになります。すなわち、

メタクラスを利用することで、クラスを実装した時点でそのクラスの定義チェックを行えます

メタクラスの使いどころ

最後にメタクラスの使いどころになると考えられているシチュエーションを挙げます。
(他にも積極的に使える場面があれば、ぜひご教示ください。)

  • クラス変数のチェックをしたい(今回のコード例)
  • インスタンス生成時に必ず特定の関数を実行したい。(デシリアライズ時にジェネリックに行えるよう、シリアライズ時にクラスの存在を登録したいときなど)

まとめ

メタクラスはクラスがどのように定義されるかを制御でき、クラス定義時のクラス変数チェックなどに有効。

参考記事

Pythonのクラスアトリビュートとメタクラスの話

Python の メタプログラミング (__metaclass__, メタクラス) を理解する

Python超入門その24〜メタクラスでクラスの動作をカスタマイズしてみよう〜

Brett Slatkin, "Effective Python", 2016, O'REILLY

41
25
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?