LoginSignup
2
0

More than 5 years have passed since last update.

メタクラスとisinstance

Posted at

発端

Djangoはモデル(django.db.models.Model)に対してメタクラスModelBaseを使い、いろいろと登録処理を行っている。

で、ソースを読んでいて、

class ModelBase(type):
    def __new__(cls, name, bases, attrs):
        parents = [b for b in bases if isinstance(b, ModelBase)]

みたいなコードがあったので「ふーん」とshellでisinstance(Question, Model)1と打ってみたところ、

False

よく考えるとわかるのだが初め「あれ?」と思ったので理解したことをまとめておく。

isinstanceとは

isinstanceは第一引数のオブジェクトが第二引数のクラスのインスタンスならTrueを返す。例えば、

isinstance(123, int)

はTrueが返る。

先の入力は何がいけなかったのか

Questionはクラス、Modelもクラス。つまり、「QuestionクラスはModelクラスのインスタンスか?」と聞いてることになる。そんなことはない。Falseが返されるのは当然だ。サブクラスとインスタンスがごっちゃになってた。

ではどう聞けばよかったのか

isinstanceとは別にissubclassという関数がある。これを使えばいい。

issublass(Question, Model)

無事Trueが返る。

メタクラスとisinstance

Djangoのソースの話に戻ろう。Djangoのソースでは「これから作成されるクラス」のスーパークラス達がModelBaseのインスタンスかを調べていた2。第一引数はクラスだ。
何故これでいいのかというと、第二引数がtypeを継承したメタクラスだから。メタクラスのインスタンスはクラスなので、このチェックはModelクラスを継承したクラスであればTrueになる。つまり、以下の式はTrueが返される。

isinstance(Question, ModelBase)

  1. QuestionはModelを継承したクラス。つまり、Djangoのモデルクラス 

  2. アプリで共通する属性を定義した抽象モデルクラスを作れるようだけど、実用上そんな複雑なモデル階層を作るのだろうか 

2
0
0

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
2
0