はじめに:Pythonの型チェックで迷っていませんか?
Pythonでプログラミングをしていると、「このオブジェクトは、本当にあのクラスのインスタンスなのかな?」とか「このクラスは、ちゃんとあのクラスを継承しているかな?」と確認したくなる場面がよくあります。
そんな時に役立つのが、Pythonに標準で用意されている isinstance() と issubclass() という2つの組み込み関数です。
しかし、名前が似ているため、 「どっちが何をする関数だっけ?」 「どう使い分ければいいの?」 と混乱してしまう方も少なくありません。
この記事を読めば、isinstance()とissubclass()の明確な違いと、それぞれの正しい使い方が分かります。具体的なコード例を交えながら丁寧に解説するので、ぜひ最後まで読んでマスターしてください!
isinstance()とは?オブジェクトの型を調べる関数
isinstance()は、指定したオブジェクト(モノ)が、特定のクラス(種類)またはそのサブクラスのインスタンスであるかどうかを判定する関数です。結果はTrueかFalseの真偽値で返されます。
isinstance()の基本的な使い方
isinstance()は、2つの引数を取ります。
isinstance(object, classinfo)object: 型を調べたいオブジェクトclassinfo: 比較対象のクラス、またはクラスのタプル
言葉だけだと分かりにくいので、早速コードを見てみましょう。
# 文字列の例
my_string = "hello"
print(f"'hello'はstr型ですか? -> {isinstance(my_string, str)}") # -> True
# 整数の例
my_int = 100
print(f"100はint型ですか? -> {isinstance(my_int, int)}") # -> True
print(f"100はstr型ですか? -> {isinstance(my_int, str)}") # -> False
# リストの例
my_list = [1, 2, 3]
print(f"[1, 2, 3]はlist型ですか? -> {isinstance(my_list, list)}") # -> Trueこのように、オブジェクトが指定したクラスから作られたインスタンスであればTrueを返します。非常に直感的で分かりやすいですね。
継承関係も考慮されるのがポイント
isinstance()の強力な点は、クラスの継承関係も考慮してくれることです。つまり、親クラスを指定した場合でも、その子クラスのインスタンスであればTrueと判定されます。
簡単な動物クラスで確認してみましょう。
Python
# 親クラス
class Animal:
pass
# 子クラス
class Dog(Animal):
pass
# インスタンスを作成
inu = Dog()
# DogはDogクラスのインスタンスか? -> True
print(f"inuはDogクラスのインスタンスですか? -> {isinstance(inu, Dog)}")
# Dogは親クラスであるAnimalクラスのインスタンスでもあると判定される
print(f"inuはAnimalクラスのインスタンスですか? -> {isinstance(inu, Animal)}")出力結果:
inuはDogクラスのインスタンスですか? -> True
inuはAnimalクラスのインスタンスですか? -> TrueDogクラスはAnimalクラスを継承しているので、DogのインスタンスであるinuはAnimalの一種と見なされます。これがisinstance()の重要な特徴です。
複数の型をまとめてチェックする方法
第2引数にクラスをタプルで渡すことで、複数の型を一度にチェックできます。いずれかの型に一致すればTrueが返ります。
value = 123.45
# valueはint型またはfloat型ですか?
is_number = isinstance(value, (int, float))
print(f"123.45はint型またはfloat型ですか? -> {is_number}") # -> True
value2 = "text"
is_number2 = isinstance(value2, (int, float))
print(f"'text'はint型またはfloat型ですか? -> {is_number2}") # -> Falseこれは、isinstance(value, int) or isinstance(value, float) と書くのと同じ意味になります。タプルを使う方が簡潔で読みやすいコードになります。
issubclass()とは?クラスの継承関係を調べる関数
issubclass()は、ある**クラス(設計図)が、別のクラス(設計図)を継承しているかどうか(サブクラスであるか)**を判定する関数です。こちらも結果はTrueかFalseで返されます。
issubclass()の基本的な使い方
issubclass()も2つの引数を取ります。
issubclass(class, classinfo)class: 判定したいクラスclassinfo: 比較対象の親クラス、または親クラスのタプル
isinstance()と違い、引数にオブジェクトではなくクラスそのものを渡す点に注意してください。
# 先ほどと同じAnimalとDogクラスを使用
class Animal:
pass
class Dog(Animal):
pass
class Cat:
pass
# DogクラスはAnimalクラスのサブクラスか? -> True
print(f"DogはAnimalのサブクラスですか? -> {issubclass(Dog, Animal)}")
# AnimalクラスはDogクラスのサブクラスか? -> False
print(f"AnimalはDogのサブクラスですか? -> {issubclass(Animal, Dog)}")
# CatクラスはAnimalクラスのサブクラスか? -> False
print(f"CatはAnimalのサブクラスですか? -> {issubclass(Cat, Animal)}")出力結果:
DogはAnimalのサブクラスですか? -> True
AnimalはDogのサブクラスですか? -> False
CatはAnimalのサブクラスですか? -> Falseこのように、クラス間の親子関係(継承関係)を直接調べることができます。
自分自身のクラスもTrueになる
issubclass()では、あるクラスは自分自身のサブクラスであると見なされます。つまり、同じクラスを比較するとTrueが返ります。
class Animal:
pass
print(f"AnimalはAnimalのサブクラスですか? -> {issubclass(Animal, Animal)}") # -> Trueこれは仕様上の挙動であり、「すべてのクラスはそれ自身のサブクラスである」と定義されています。
決定的な違い:「モノ」を調べるか「設計図」を調べるか
isinstance()とissubclass()の最も重要な違いを、一言でまとめます。
isinstance(): **オブジェクト(モノ)**が、特定のクラスから作られたものかを調べる。issubclass(): **クラス(設計図)**が、別のクラスを継承しているかを調べる。
ポイントは「インスタンス」と「クラス」
inu = Dog() というコードがあった場合、
inuはDogクラスから作られた**インスタンス(オブジェクト)**です。DogやAnimalはクラスです。
この違いを意識すれば、isinstance(inu, Dog)のように「インスタンス」を調べるのがisinstance()で、issubclass(Dog, Animal)のように「クラス」を調べるのがissubclass()だと、迷うことはなくなるでしょう。
使い分けの簡単ガイド
| やりたいこと | 使う関数 | 例 |
変数xの中身が数値(intやfloat)か調べたい | isinstance() | isinstance(x, (int, float)) |
MyClassがBaseClassを継承しているか確認したい | issubclass() | issubclass(MyClass, BaseClass) |
受け取った引数がUserクラスのオブジェクトか調べたい | isinstance() | isinstance(user_obj, User) |
Google スプレッドシートにエクスポート
参考:type()との違い
isinstance()とよく比較されるのがtype()関数です。type(obj) == MyClass のように型を比較できますが、これは継承関係を考慮しません。
class Animal:
pass
class Dog(Animal):
pass
inu = Dog()
print(f"type(inu) == Dog -> {type(inu) == Dog}") # -> True
print(f"type(inu) == Animal -> {type(inu) == Animal}") # -> False
print(f"isinstance(inu, Animal) -> {isinstance(inu, Animal)}") # -> Truetype()は厳密に型が一致するかどうかしか見ませんが、isinstance()は継承関係を遡ってチェックします。柔軟な型チェックを行いたい場合は、type()よりもisinstance()を使うのが一般的です。
実践的な使い方
関数の引数チェックで安全なコードを書く
関数の引数として特定の型のオブジェクトを期待する場合、isinstance()を使って型チェックを行うことで、予期せぬエラーを防ぎ、コードの堅牢性を高めることができます。
def process_data(data):
# dataがリストでなければ処理を中断
if not isinstance(data, list):
raise TypeError("引数dataはリストである必要があります")
# リストに対する処理
for item in data:
print(item)
# 正しい使い方
process_data([1, 2, 3])
# 間違った使い方(TypeErrorが発生)
# process_data("hello")ポリモーフィズムと組み合わせて柔軟な処理を実現
ポリモーフィズム(多態性)を活かしたコーディングでは、オブジェクトの種類に応じて処理を分岐させたい場合があります。isinstance()を使えば、これをスマートに実装できます。
class Dog:
def speak(self):
return "ワン!"
class Cat:
def speak(self):
return "ニャー"
def animal_sound(animal):
if isinstance(animal, (Dog, Cat)):
print(animal.speak())
else:
print("犬か猫ではありません")
inu = Dog()
neko = Cat()
animal_sound(inu) # -> ワン!
animal_sound(neko) # -> ニャーまとめ
今回は、Pythonのisinstance()とissubclass()について、その違いと使い方を解説しました。最後に重要なポイントをまとめます。
isinstance(object, class): オブジェクトが特定のクラス(またはそのサブクラス)のインスタンスか調べる。issubclass(class, class): あるクラスが別のクラスのサブクラス(継承関係にある)か調べる。- チェック対象が「モノ(インスタンス)」なのか「設計図(クラス)」なのかを意識するのが使い分けの鍵。
- 継承関係を考慮した柔軟な型チェックには
type()ではなくisinstance()を使うのが一般的。
この2つの関数を正しく使い分けることで、より安全で読みやすいPythonコードを書くことができます。ぜひ今後のコーディングに活かしてみてください。


コメント