閉じる

Pythonのisinstance()とtype()の違いまとめ: 正しい使い分け

Pythonで型判定を行う際、isinstance()type()は似ているようで目的が異なります。

初心者の方が混乱しやすい点は、継承を考慮するかどうかです。

本記事では、両者の違いを明確にし、実用的な使い分けベストプラクティスをサンプルコードとともに丁寧に解説します。

Pythonのisinstance()とtype()の違い

継承を考慮する型判定はisinstance

基本の考え方とシグネチャ

isinstance(obj, cls_or_tuple)は、サブクラスも含めて判定します。

第2引数にはクラス(型)か、クラス(型)のタプルを渡せます。

つまり、ある抽象的な「系統」に属するかどうかを調べるのに向いています。

Python
# 継承関係を持つクラスを定義
class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()

# isinstance はサブクラスを「親としても」認める
print(isinstance(dog, Dog))     # Dogのインスタンスか
print(isinstance(dog, Animal))  # Animal(親)としても扱えるか
実行結果
True
True

タプル指定で複数型を許容

複数の受け入れ可能な型を並べるときは、タプルで渡します。

これにより冗長な条件分岐を避け、読みやすく安全なコードになります。

詳細は後述の「複数の許容型はisinstanceのタプル指定が便利」を参照してください。

厳密な型一致の確認はtypeで比較

type()は「ぴったり一致」を見る

type(obj) is SomeClassのように比較すると、サブクラスを認めません

厳密な一致が必要なときに使います。

例えば、サブクラスを誤って受け入れたくない場合に有効です。

Python
class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()

print(type(dog) is Dog)     # ぴったりDogか
print(type(dog) is Animal)  # 親クラスAnimalそのものか
実行結果
True
False

比較演算子はisが基本

type(obj) == SomeClassより、type(obj) is SomeClassを用いるのが一般的です。

クラスオブジェクトは単一性が保証されるため、isでの同一性比較が適切です。

組み込み型とユーザー定義クラスでの挙動の差

代表的な違いを早見表で整理

観点isinstance(obj, 型)type(obj) is 型
継承を考慮するしない
複数型を一度に判定可能(タプル指定)不可
代表的な用途インターフェースや系統(親子関係)の確認厳密な一致、サブクラス除外
注意点過剰に使うとダックタイピングを阻害継承を無視してしまう

特にboolはintのサブクラス(Python仕様)である点は初心者がつまずきやすいです。

isinstance(True, int)はTrueになりますが、type(True) is intはFalseです。

詳細は「Noneやboolなど特殊ケースの型判定のコツ」で扱います。

Pythonでの正しい使い分け

サブクラスやインターフェース判定はisinstanceが安全

継承を活かすAPIではisinstance

ライブラリやアプリケーションのAPIで拡張(サブクラス)を受け入れたいとき、isinstanceを使うと柔軟性を保てます。

例えば、Animalを受け入れる関数は、DogCatなどのサブクラスも自然に扱えます。

Python
class Animal:
    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return "woof"

def call_speak(x):
    # Animal系を受け入れる設計
    if not isinstance(x, Animal):
        raise TypeError("Animalの系統ではありません")
    return x.speak()

print(call_speak(Dog()))
実行結果
woof

複数の許容型はisinstanceのタプル指定が便利

bytes/bytearray/strを受け入れる例

外部入力では文字列かバイト列かを柔軟に扱いたい場面が多いです。

そんなときはタプル指定で分かりやすく書けます。

Python
# 受け取った値を「文字列」に正規化する関数
def normalize_to_str(x):
    # bytes と bytearray のどちらも許容
    if isinstance(x, (bytes, bytearray)):
        # bytearrayもbytesに変換すればdecode可能
        x = bytes(x)
        return x.decode("utf-8")
    elif isinstance(x, str):
        return x
    else:
        raise TypeError("str, bytes, bytearrayのみ受け付けます")

print(normalize_to_str(b"hello"))                 # bytes
print(normalize_to_str(bytearray(b"hi")))         # bytearray
print(normalize_to_str("こんにちは"))                # str
実行結果
hello
hi
こんにちは

Noneやboolなど特殊ケースの型判定のコツ

Noneは型判定しない。

「is None」を使う

Noneチェックはis Noneが定石です。

type(x) is NoneTypeのような書き方は避けます。

Python
x = None

# Noneかどうかは同一性で判定するのが正解
if x is None:
    print("xはNoneです")
else:
    print("xはNoneではありません")
実行結果
xはNoneです

boolはintのサブクラスである

isinstance(True, int)はTrueです。

真偽値を整数として数えたくない場面では注意します。

Python
print(isinstance(True, int))   # boolはintのサブクラスなのでTrue
print(isinstance(True, bool))  # もちろんTrue
print(type(True) is int)       # 厳密にintそのものか → False
print(type(True) is bool)      # 厳密にboolそのものか → True

def want_int_but_not_bool(x):
    # boolを明確に除外してからint判定
    if isinstance(x, bool):
        raise TypeError("boolは除外します")
    if not isinstance(x, int):
        raise TypeError("intが必要です")
    return x + 1

print(want_int_but_not_bool(10))
実行結果
True
True
False
True
11

型判定のベストプラクティス

ダックタイピングを優先しisinstanceは最小限に

EAFP(まず試して、ダメなら例外)のスタイル

Pythonでは「できるかどうか」を型ではなく振る舞いで判断するのが自然です。

ダックタイピング(アヒルのように歩き鳴くなら、それはアヒル)を優先し、必要最小限の場面だけisinstanceを使います。

Python
# 先頭要素を取りたい。「シーケンスか?」ではなく「添字アクセスできるか?」で判断
def head(seq):
    try:
        return seq[0]  # 添字アクセスできればOK
    except (TypeError, IndexError):
        return None

print(head([1, 2, 3]))     # リスト
print(head("abc"))         # 文字列
print(head(123))           # 添字不可 → None
実行結果
1
a
None

抽象基底クラスcollections.abcでのisinstance活用

ABCを使うと「インターフェース」による判定ができる

collections.abcSequenceMappingなどの抽象基底クラス(ABC)でインターフェース判定が可能です。

自作クラスが対応メソッドを実装すれば、isinstanceで「その振る舞いを持つ」と認められます。

Python
from collections.abc import Sequence, Mapping, Iterable

def first_three(x):
    if isinstance(x, Sequence):   # シーケンスプロトコル(順序・添字・len)
        return x[:3]
    raise TypeError("Sequenceではありません")

print(isinstance([1, 2, 3], Sequence))     # listはSequence
print(isinstance({"a": 1}, Mapping))       # dictはMapping
print(isinstance((i for i in range(3)), Iterable))  # ジェネレータはIterable
print(first_three(("A", "B", "C", "D")))  # タプルにも適用
実行結果
True
True
True
('A', 'B', 'C')

アンチパターンとパフォーマンスの注意点

避けたいアンチパターン

  • type比較でサブクラスを排除してしまう: 拡張性が必要なAPIではisinstanceを使いましょう。
  • 型分岐が過剰: まずはポリモーフィズム(各クラスに共通メソッドを持たせる)やダックタイピングで設計を見直します。
  • Noneをtypeで判定: is Noneを使います。

パフォーマンスの話

isinstancetype自体は高速ですが、無意味な回数の判定は避けるべきです。

熱いループ内では、ifの外で一度だけ判定する、責務を分離して分岐自体をなくすなど、設計で最適化するのが効果的です。

まとめとチェックリスト

isinstanceを使う場面とtypeを使う場面の整理

  • isinstance: 継承やインターフェース(ABC)を考慮して受け入れたいとき。複数型許容はタプルで簡潔に。
  • type(… ) is …: サブクラスを厳密に排除したいときや、完全一致を保証したいとき。

初心者が避けたい型判定の落とし穴

  • Noneチェックにtypeを使わない(is Noneを使う)。
  • boolはintのサブクラスであることを理解し、整数扱いしたくない場合は除外する。
  • ダックタイピングを忘れない。まずは「できるか」で判定し、やむを得ないときだけ型を見る。
  • 拡張性が必要なAPIでtype比較を使わない。サブクラスを受け入れられるようisinstanceを選ぶ。

まとめ

isinstance()は継承や抽象基底クラスを考慮した柔軟な判定、type()はサブクラスを排除する厳密な一致確認に適しています。

Noneはis Noneで判定し、boolがintのサブクラスである点に注意します。

実務ではダックタイピングを優先し、必要最小限の型判定に留めることが読みやすさと拡張性につながります。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!