Python | 関数:isinstance

Python
スポンサーリンク

概要(isinstance は「型やサブクラスまで含めた安全な型チェック」)

isinstance は、渡した値が指定した型(クラス)か、またはそのサブクラスであるかを真偽値で返す組み込み関数です。Python は継承や抽象型(インターフェース)を多用します。単純な一致判定よりも「その型として扱ってよいか」を判断する場面で、isinstance が正解になります。

print(isinstance(10, int))         # True
print(isinstance(True, int))       # True(bool は int のサブクラス)
print(isinstance([1, 2], (list, tuple)))  # True(複数型を許容)
Python

基本構文と動作(ここが重要)

2引数の基本形と複数型の許容

isinstance(obj, classinfo) の形で使います。classinfo には単一の型または「型のタプル」を渡せます。タプルを使うと、複数の型をまとめて許容できます。

print(isinstance("hello", str))               # True
print(isinstance(3.14, (int, float)))         # True
print(isinstance({"a": 1}, (list, dict)))     # True(dict を許容)
Python

継承関係を考慮する(親クラスでも True)

サブクラスのインスタンスは、親クラスに対しても True になります。抽象基底クラス(ABC)や“インターフェース的な”型に対してのチェックが自然に書けます。

class Animal: ...
class Dog(Animal): ...

d = Dog()
print(isinstance(d, Dog))     # True
print(isinstance(d, Animal))  # True(親クラス)
Python

type との違い(厳密一致か、実務的な「扱えるか」か)を深掘り

type は“完全一致”、isinstance は“扱える範囲”

type(x) is T は「実体が T そのものか」を見る厳密判定。isinstance(x, T) は「T として扱ってよいか」を見る柔軟判定です。ライブラリ間でクラスが拡張される現場では、原則 isinstance を選びます。

class A: ...
class B(A): ...
b = B()

print(type(b) is A)      # False
print(isinstance(b, A))  # True
Python

代表的な落とし穴(bool は int のサブクラス)

True/False は int を継承しています。数値のみ受けたいが「真偽値を除外したい」なら、isinstance で数値を許容したあとに bool を明示的に弾く、または最初に type(x) is bool を除外します。

def square(x):
    if type(x) is bool:            # 先に厳密除外
        raise TypeError("bool は数値扱いしません")
    if isinstance(x, (int, float)):
        return x * x
    raise TypeError("数値のみ受け付けます")
Python

抽象基底クラス(ABC)で「振る舞いの型」をチェック

コレクション系の ABC を使うと意図が伝わる

「シーケンス(順番に並んだ要素)なら OK」「マッピング(キー→値)なら OK」など、構造や振る舞いで受けたいときは collections.abc の型を使います。派生クラスも自然に拾えます。

from collections.abc import Sequence, Mapping

def head(xs):
    if not isinstance(xs, Sequence):
        raise TypeError("シーケンスを渡してください")
    return xs[0] if xs else None

def total(m):
    if not isinstance(m, Mapping):
        raise TypeError("マッピング(dict 等)を渡してください")
    return sum(m.values())
Python

文字列は「シーケンスでもある」ことに注意

str は Sequence の一種です。文字列を“要素集合”として扱いたくない場合は、先に isinstance(x, str) を除外してから Sequence を判定します。

from collections.abc import Sequence

def avg(xs):
    if isinstance(xs, str):
        raise TypeError("文字列は対象外です")
    if not isinstance(xs, Sequence):
        raise TypeError("数値のシーケンスを渡してください")
    return sum(xs) / len(xs)
Python

実務での使いどころ(入力検証・分岐・フォールバック)

入力検証で「受け入れる範囲」を明示する

ユーザー入力や外部データは型が揺れます。最初に isinstance で受け入れ可能範囲を絞ると、後続のロジックが安定します。

def parse_int(x):
    if isinstance(x, int):
        return x
    if isinstance(x, str) and x.isdigit():
        return int(x)
    raise TypeError("整数または数字文字列を渡してください")
Python

型ごとの分岐を読みやすく整理する

複数型を受ける関数は、型判定を上から順に短く書いて早期 return。可読性が上がり、バグが減ります。

def to_list(x):
    if isinstance(x, list):
        return x
    if isinstance(x, tuple):
        return list(x)
    if isinstance(x, str):
        return [x]
    raise TypeError("list/tuple/str のみ対応です")
Python

ロギングやデバッグに型情報を添える

isinstance と組み合わせて「どの分岐に入ったか」を明示しておくと、障害調査の初期対応が速くなります。

def debug_route(x):
    if isinstance(x, dict):
        print("route=dict")
    elif isinstance(x, (list, tuple)):
        print("route=sequence")
    else:
        print("route=other")
Python

応用と設計の勘所(duck typingとの線引き・型ヒントとの併用)

“duck typing”に寄せるか、isinstanceで守るか

Python は「そのメソッドが使えれば良い」という考え(duck typing)も強力です。外部入力の入口や公開 API では isinstance で防御的に。内部のホットパスでは try/except でメソッドを直接呼ぶ方が軽量な場合もあります。入口は厳しく、中は軽く、が基本のバランスです。

def safe_len(x):
    # 入口なら isinstance(Sequence) の検証でも良い
    try:
        return len(x)
    except TypeError:
        raise TypeError("長さを持つオブジェクトを渡してください")
Python

型ヒントと補完のための設計

isinstance によるガードは、型ヒント(typing)と相性が良いです。入口で型を絞れば、IDE の補完も安定し、静的解析ツールの誤検知が減ります。

from typing import Iterable

def mean(xs: Iterable[float]) -> float:
    # 実際の受け入れは isinstance(xs, Iterable) で守る選択肢も
    total = 0.0
    count = 0
    for x in xs:
        total += x
        count += 1
    return total / count if count else 0.0
Python

例題で身につける(定番から一歩先まで)

例題1:数値だけを受ける(bool 除外)

def area_of_square(x):
    if type(x) is bool:
        raise TypeError("True/False は数値として扱いません")
    if not isinstance(x, (int, float)):
        raise TypeError("数値を渡してください")
    return x * x

print(area_of_square(3.5))  # 12.25
Python

例題2:複数型を許容して正規化

def as_dict(x):
    if isinstance(x, dict):
        return x
    if isinstance(x, (list, tuple)):
        # [("k","v"), ...] を dict に
        return dict(x)
    raise TypeError("dict か (key, value) の列を渡してください")

print(as_dict([("a", 1), ("b", 2)]))  # {'a': 1, 'b': 2}
Python

例題3:ABC を使ったインターフェース受け

from collections.abc import Sequence

def tail(xs):
    if not isinstance(xs, Sequence):
        raise TypeError("シーケンスを渡してください")
    return xs[-1] if xs else None

print(tail((1, 2, 3)))  # 3
Python

例題4:クラス階層での柔軟な受付

class Shape: ...
class Circle(Shape): ...
class Square(Shape): ...

def draw(s):
    if not isinstance(s, Shape):
        raise TypeError("Shape 系のオブジェクトを渡してください")
    return f"drawing {type(s).__name__}"

print(draw(Circle()))
print(draw(Square()))
Python

まとめ

isinstance は「この値をその型として扱ってよいか」を継承関係まで含めて判定できる、Python で最も実務的な型チェック手段です。type は厳密一致、isinstance は柔軟判定。bool が int のサブクラスという落とし穴、文字列がシーケンスである点、ABC による振る舞いチェック——これらを理解すると、入力検証・分岐・ロギングが安定し、初心者のコードは一段読みやすく堅牢になります。入口は厳しく、中は軽く。型を味方にして、意図が伝わる関数を書いていきましょう。

タイトルとURLをコピーしました