<一覧に戻る

issubclass() を使ったクラスのチェック

「このクラス、親子関係はどうなっているんだろう?」と迷ったことはありませんか。

Pythonでは、クラス同士の関係(継承)を簡単に調べるための関数としてissubclass()が用意されています。

プログラムの規模が大きくなるほど、正しい継承関係を把握することは、バグを避けるうえでもとても大切です。ここでは Python 初心者・IT 初心者の方にもわかりやすく、issubclass() の基本から実用的な使い方、つまずきやすいポイントまで丁寧に解説します。

issubclass() 関数の基本

issubclass() はあるクラスが別のクラスのサブクラス(子クラス)かどうかを True/False で判定します。第二引数には単一のクラスだけでなく、クラスのタプルも渡せます。

つまり「このどれかの親に当たる?」という複数チェックも一度にできます。

構文は次のとおりです。

issubclass(subclass, superclass_or_tuple)
  • 第一引数には調べたいクラス(サブクラス候補)を渡します。
  • 第二引数には親クラス、または親クラスのタプルを渡します。

「クラスの関係を安全に確認したい」「条件分岐でクラスごとに処理を分けたい」といった場面で、とても頼りになる関数です。

基本的な使い方

まずはシンプルな継承関係で動作を確認しましょう。

class Animal:
    pass

class Dog(Animal):
    pass

class Cat(Animal):
    pass

# DogはAnimalのサブクラスか?
print(issubclass(Dog, Animal))  # True

# CatはAnimalのサブクラスか?
print(issubclass(Cat, Animal))  # True

# AnimalはDogのサブクラスか?
print(issubclass(Animal, Dog))  # False

Animal を親に持つ Dog と Cat は、どちらも Animal のサブクラスなので True が返ります。一方で、親である Animal は子である Dog のサブクラスではありませんから False になります。ここで覚えておきたいのは、直接の親子関係だけでなく「間接的な親子関係」でも True になることです。例えば「A → B → C」と継承が続くとき、C は A のサブクラスとみなされます。

多重継承や継承チェーンでのチェック

Python は多重継承をサポートしています。issubclass() は多重継承や継承が何段にも連なる場合でも、正しく関係をたどって判定してくれます。

class Pet:
    pass

class Trainable:
    pass

class Dog(Pet, Trainable):
    pass

class ServiceDog(Dog):
    pass

print(issubclass(ServiceDog, Dog))       # True(直接の親)
print(issubclass(ServiceDog, Pet))       # True(祖先クラス)
print(issubclass(ServiceDog, Trainable)) # True(もう一方の祖先)
print(issubclass(Dog, ServiceDog))       # False(親は子のサブクラスではない)

ServiceDog は Dog を継承しており、Dog は Pet と Trainable を同時に継承しています。 このような複合的な関係でも、issubclass() は系譜をさかのぼって True/False を返します。複雑な階層でも見失わないのが心強いですね。

組み込み型でも使える

issubclass() はユーザー定義クラスだけでなく、list や dict といった組み込み型にも使えます。 Python のすべての新スタイルクラスは最終的に object を継承しているため、次のように判定できます。

print(issubclass(list, object))  # True
print(issubclass(dict, list))    # False

もう一つ、初心者が驚きやすいポイントとして「bool は int のサブクラス」という仕様があります。

print(issubclass(bool, int))  # True

True/False は内部的には 1/0 としてふるまえるため、bool は int の特別なサブクラスとして定義されています。型チェックや条件分岐で「なぜ通ってしまうの?」と悩んだときに役立つ知識です。

親クラスをまとめてチェック(タプルを使う)

「このクラス、A か B のどちらかのサブクラスなら OK」といった複数条件を、一度に判定したくなることはありませんか。第二引数にタプルを渡すと、いずれかに当てはまれば True になります。

class Bird: pass
class Flyer: pass

class Eagle(Bird, Flyer): pass

print(issubclass(Eagle, (Bird, Flyer)))  # True(どちらにも当てはまる)
print(issubclass(Bird, (Flyer, dict)))   # False(どちらにも当てはまらない)

複数の型を許容する API を作るときなどに、シンプルなコードで堅牢なチェックが書けます。

クラスではなく「インスタンス」を渡すとエラー

issubclass() はクラス同士を比較する関数です。もしインスタンス(生成したオブジェクト)を第一引数に渡すと、TypeError が発生します。

初学者が最初に引っかかりやすいポイントなので注意しましょう。

class Animal: pass
class Dog(Animal): pass

d = Dog()

# 間違い:インスタンス d を渡している
# issubclass(d, Animal)  # TypeError: issubclass() arg 1 must be a class

# 正しくはクラスを渡す
print(issubclass(Dog, Animal))  # True

「インスタンスが特定のクラス(またはそのサブクラス)かどうか」を調べたい場合は isinstance() を使います。このあと別セクション「isinstance() を使ったインスタンスのチェック」で詳しく扱いますので、併せて確認してみてください。

抽象クラス(ABC)や“仮想”サブクラスとの関係

抽象基底クラス(Abstract Base Class、ABC)を使うと、明示的に継承していなくても「登録(register)」によって仮想的なサブクラスとみなせます。issubclass() はこの“仮想サブクラス”も True と判定します。

from abc import ABC, abstractmethod

class FileLike(ABC):
    @abstractmethod
    def read(self) -> bytes: ...
    @abstractmethod
    def write(self, data: bytes) -> int: ...

class SocketStream:
    def read(self) -> bytes:
        return b"..."
    def write(self, data: bytes) -> int:
        return len(data)

# 直接継承していないが、FileLike の契約を満たす前提で登録
FileLike.register(SocketStream)

print(issubclass(SocketStream, FileLike))  # True(仮想サブクラス)

「実装は満たしているが継承関係は持たせない」という設計でも、issubclass() は ABC の仕組みを理解して正しく判定してくれます。抽象クラスやプロトコル設計と一緒に使うと、型安全性と柔軟性を両立できます。

型・継承の見取り図を安全に確認しよう

今回学習した内容をまとめます。

  • クラス間の親子関係を True/False で手早く確かめたいなら、issubclass() が最適です。
  • 第二引数にタプルを渡せば、複数の候補をまとめて判定できます。
  • 組み込み型にも使え、bool と int の関係など言語仕様の理解にも役立ちます。
  • インスタンスを渡すとエラーになる点だけは要注意。インスタンスのチェックには isinstance() を使い分けましょう。
  • ABC の“仮想サブクラス”にも対応しており、現代的な Python の型設計と相性抜群です。

「このクラス、本当にこの親クラスの流儀に従っている?」と不安になったとき、まずは issubclass() で確かめてみましょう。継承関係の見取り図がクリアになれば、コードの可読性も保守性もグッと上がります。

出力結果: