あるクラスが別のクラスのサブクラスかどうかを(実行時に)確認するにはどうすればよいですか?


196

クラスSuitと、スーツの4つのサブクラス、Heart、Spade、Diamond、Clubがあるとします。

class Suit:
   ...
class Heart(Suit):
   ...
class Spade(Suit):
   ...
class Diamond(Suit):
   ...
class Club(Suit):
   ...

インスタンスとしてではなく、クラスオブジェクトであるスーツをパラメーターとして受け取るメソッドがあります。より正確には、ハート、スペード、ダイアモンド、クラブの4つの値の1つのみを受け取ることができます。このようなことを保証するアサーションを作成するにはどうすればよいですか?何かのようなもの:

def my_method(suit):
   assert(suit subclass of Suit)
   ...

私はPython 3を使用しています。


1
@Leopd:本当にわからないの?my_methodパラメータとして取得できる4つの値は何であるかを正確に述べました。「ハート、スペード、ダイアモンド、クラブの4つの値のうちの1つだけを受け取る可能性があります」。これらの値はクラスオブジェクトであり、クラスインスタンスではありません。答えは両方の可能性をカバーしているので、曖昧さについてはあなたが正しいと思いますが、それは私にはかなり明白に思えます。より明確な語彙があれば、質問を編集することは大歓迎です。コメントをありがとう。
スナキレ

@snakileはい、不明確です。このトピックでは、誰かの自己表現の正確さに依存しているために、氷が薄くなっています。多くの新規参入者は、すべてがPythonのオブジェクトであるということを得ることができず、あることを表現しても別のものを考えるかもしれません。それは現実であり、純粋さはさておき、この動作を初心者に期待することは非常に合理的です。あなたの評判を離れることは、ここでのあなたの表現が正しいかどうか、または「正確さの観点から」と私が言うべきかどうかの唯一の直接的なヒントを示します。私はあなたの知識を考慮に入れたいという願いを理解しています。そして、絶えず更新されている新参者を考慮に入れないことは依然として不合理です。
n611x007 14

1
@snakile、およびそのようなパラメータ名に接尾辞を付けるような命名規則を使用して_class、それらをのようにすることが合理的である可能性があることsuit_class。私は関連する質問でそのような命名規則を提案しまし
n611x007 14

サンプルコードに4行追加することを提案しmy_method(Heart) my_method(Spade)ます...
Bob Stein

テストされる変数がクラスであることが保証されていない場合は、非クラスが渡されるとエラーが発生するため、条件を追加するinspect.isclassか、単にisinstance(myvar, type)Python 3で使用できますissubclass。この回答を参照してください。私は以下の答えについてコメントしたでしょうが、それは日の目を見たことはありませんでした。
totalhack

回答:


224

issubclass()このように使えますassert issubclass(suit, Suit)


55
「でも、なぜそんなことをしたいのですか?」-確実に同種であることを確認する必要があるコンテナクラスがあり、それを行う唯一の方法は挿入時に型をチェックすることですか?
アダムパーキン

139
スタックオーバーフローで一定していることが1つあるとすれば、isinstanceまたはissubclassを示唆する回答のある質問には、ダックタイピングに関する講義も伴うということです。
ベンロバーツ

26
私の派手なdtypeが画像処理アプリケーションのfloatまたはintであるかどうかを検出する方法を見つけようとしているこの質問に出くわしました。フロートの場合、規則は0.0と1.0の間で正規化することです。整数の場合、規則は0から255です。あらゆる種類のゆがみをたどってイメージを揺さぶることができますが、もっと簡単です。 「あなたはアヒルですか」と聞いて、それに応じて私の操作を拡大してください。
オメガマン2014年

28
サブクラスのテストは、多くのこと、特にDjangoのモデルのユニットテストをはるかに簡単にします。「PythonはJavaではありません。」なぜPythonプログラマーはそのようなチップを肩にかざす必要があるのでしょうか?
マイケルベーコン

20
純粋に終わりの想像力に欠ける傲慢な発言のために、賛成票を投じない。これを行う必要がない理由についての説明は、より親しみやすく、より役立つでしょう。
Michael Scheper、2016年


26

isinstanceインスタンスがある場合、またはissubclassクラスがある場合に使用できます。通常は悪い考えだと思いました。通常、Pythonでは、オブジェクトに何かを実行しようとすることで、オブジェクトが何かに対応できるかどうかを判断します。


あなたがそれでそれを行うことができないとわかったらどうしますか?例外をキャッチして他のことを試しますか?
wrongusername

2
@wrongusername:それが「Pythonic」のやり方です。このカスタムにはメリットがあると思うので、コードが明確に保たれている限り、それに従います。この程度の良い議論がここにあります:stackoverflow.com/questions/7604636/...
マイケルScheper

8
@Michael Scheper:私が言わなければならないのは、それがpythonicのやり方だとしたら、私は本当にpythonicのやり方が嫌いだ。IMO、例外を制御フローに使用しないでください。エラーが発生する可能性があると思われる場合は、エラーから保護してください。GOTOのように扱わないでください。しかし、あなたが投稿した興味深いリンク
leviathanbadger 2017

@ aboveyou00:あなたが話しているようなケースは、「私のコードを明確に保つ限り」に違反するように聞こえます。ただし、多くの人がEAFPの原則を悪用し、見つけにくいバグを作成してしまうため、私はすべてのPythonicの習慣のファンではありません。
Michael Scheper

このチェックは、契約を定義するときに便利です。たとえば、オブジェクトを受け取るコンストラクター:受け取ったオブジェクトが特定のクラスのインスタンスであることをアサートしたいので、コンストラクターが期待することをコードリーダーに通知します。
mastropi


2

issubclass 最小限の実行可能な例

これは、いくつかのアサーションを含むより完全な例です。

#!/usr/bin/env python3

class Base:
    pass

class Derived(Base):
    pass

base = Base()
derived = Derived()

# Basic usage.
assert issubclass(Derived, Base)
assert not issubclass(Base, Derived)

# True for same object.
assert issubclass(Base, Base)

# Cannot use object of class.
try:
    issubclass(derived, Base)
except TypeError:
    pass
else:
    assert False

# Do this instead.
assert isinstance(derived, Base)

GitHubアップストリーム

Python 3.5.2でテスト済み。


1

組み込みのissubclassを使用できます。ただし、アヒルのタイピングを使用できるため、タイプチェックは通常不要と見なされます。


1

issubclassを使用すると、ログレベルを書き込むためのクリーンな方法のように見えました。それを使用するのはちょっと変に感じます...しかし、それは他のオプションよりもきれいに見えます。

class Error(object): pass
class Warn(Error): pass
class Info(Warn): pass
class Debug(Info): pass

class Logger():
    LEVEL = Info

    @staticmethod
    def log(text,level):
        if issubclass(Logger.LEVEL,level):
            print(text)
    @staticmethod
    def debug(text):
        Logger.log(text,Debug)   
    @staticmethod
    def info(text):
        Logger.log(text,Info)
    @staticmethod
    def warn(text):
        Logger.log(text,Warn)
    @staticmethod
    def error(text):
        Logger.log(text,Error)

0

Python docによると、class.__mro__属性またはclass.mro()メソッドを使用することもできます。

class Suit:
    pass
class Heart(Suit):
    pass
class Spade(Suit):
    pass
class Diamond(Suit):
    pass
class Club(Suit):
    pass

>>> Heart.mro()
[<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>]
>>> Heart.__mro__
(<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>)

Suit in Heart.mro()  # True
object in Heart.__mro__  # True
Spade in Heart.mro()  # False

-5
#issubclass(child,parent)

class a:
    pass
class b(a):
    pass
class c(b):
    pass

print(issubclass(c,b))#it returns true

1
コードのみの回答はSOでは認められません。常にコードに説明テキストを追加する必要があります。ただし、この回答は不必要です。以前の回答でまだ言及されていない情報は追加されません。
PM 2Ring 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.