web-dev-qa-db-ja.com

Pythonタイプヒント:XがFooのサブクラスであることをどのように伝えるか?

Pythonでクラス型の型ヒントをどのように記述する必要がありますか?このコードを考えてみましょう:

class A(object):
    pass

class B(A):
    pass

def register(cls: type[A]):
    assert issubclass(cls, A)

 register(A)
 register(B)

type[A]これを書く正しい方法は? cls: Aは、clsAのインスタンスであることを意味しますが、clsは少なくともサブクラスAであるクラス/タイプであると言いたいです。

具体的には、パラメーターがDjangoモデルタイプである必要があります。

32
vdboor

ここでの他の現在(2016年9月22日)の回答は正しくないようです。 PEP 484(タイプヒントについて)によると、クラスオブジェクトのタイプに関するヒントが存在します。これは Type [C] と呼ばれます。そして、typingモジュールのドキュメントによると、あなたは typing.Type [C] を使ってあなたが望むものを正確に達成することができます。私はPython 3.5.2。

引用 the PEP

クラスオブジェクト、特に特定のクラスから継承するクラスオブジェクトについて話したい場合があります。これはType [C]と綴ることができ、Cはクラスです。明確にするために:C(注釈として使用される場合)はクラスCのインスタンスを参照しますが、Type [C]はCのサブクラスを参照します。

そして引用 ドキュメント

Cで注釈された変数は、タイプCの値を受け入れることができます。対照的に、Type [C]で注釈された変数は、それ自体がクラスである値を受け入れることができます。具体的には、Cのクラスオブジェクトを受け入れます。

そしてあなたの特定の例を参照してください:

import typing

class A(object):
    pass

class B(A):
    pass

def register(cls: typing.Type[A]):
    assert issubclass(cls, A)

register(A)
register(B)

このようなコードは mypy を使用して静的にチェックでき、簡単なケースで機能するはずです。ただし、mypyはまだ作業中であることに注意してください。現在、Type [C]ヒンティングに関していくつかの問題が未解決です。

32
mbdevpl

一般的なケースを解決するには、適切な___subclasscheck___を使用してメタクラスを記述する必要があります。可能ですが面倒です。

Djangoモデルクラスの特定のケースでは、明示的なメタクラスがすでに存在しているので、注釈を付けると次のようになります。

_import Django.db.model as model

def register(cls: model.base.ModelBase): ...
_

これは、isinstance(models.Model, models.base.ModelBase)がtrueであるため機能します。

3
Lutz Prechelt