Pythonの型判定は、基本的に isinstance(x, 型) を使います。isinstance は継承したクラス(サブクラス)も「その型」として認めるのに対し、type(x) は「その値を作ったクラスそのもの」を返すので、type(x) is 型 は完全一致だけを調べたいときに使う、という使い分けです。 型の名前を画面に出して確認したいだけなら type(x) や type(x).__name__ で十分です。

この記事では、同じ値に対して type() と isinstance() を実行した結果を横に並べた早見表を最初に示し、そのあとで継承、bool と int の関係、None、複数の型をまとめて調べる書き方、collections.abc や numbers を使った「性質」での判定、NumPy の型、match 文、そのまま貼って使える判定関数集までを順に説明します。掲載した出力はすべて Python 3.11.15 で実行したもので、同じスクリプトを Python 3.14.7(NumPy 2.4.4)でも動かし、注記した1か所を除いて同じ結果になることを確認しています。

型判定の早見表(type と isinstance の実行結果を横並び)

まず「どの書き方を選ぶか」の一覧です。

やりたいこと 書き方 ポイント
型を画面に出して確認したい print(type(x)) / type(x).__name__ デバッグ向け。判定には使わなくてよい
ある型か(サブクラスも含めて)調べたい isinstance(x, int) ふだんはこれ
複数の型のどれかか調べたい isinstance(x, (int, float)) / isinstance(x, int | float) タプルは全バージョン、| は 3.10 以降
その型ちょうど(サブクラスを除く)か調べたい type(x) is int bool を int から除きたいときなど
None か調べたい x is None isinstance より is が定番
ループで回せるか調べたい isinstance(x, collections.abc.Iterable) 文字列も True になる点に注意
辞書のように使えるか調べたい isinstance(x, collections.abc.Mapping) dict 以外の辞書風オブジェクトも拾える
数値か調べたい isinstance(x, numbers.Number) Decimal や NumPy の数値も True
クラス同士の親子関係を調べたい issubclass(Dog, Animal) 第1引数はクラス
型ごとに処理を分けたい match x: と case int(): 3.10 以降。中身の取り出しも同時にできる

次に、同じ値を type() と isinstance() に渡した実行結果です。T は True、F は False を表します。

値 type(x).__name__ type(x) == int isinstance(x, int) isinstance(x, (int, float)) numbers.Number abc.Iterable abc.Sequence abc.Mapping
1 int T T T T F F F
True bool F T T T F F F
1.5 float F F T T F F F
'a' str F F F F T T F
None NoneType F F F F F F F
[1] list F F F F T T F
(1,) tuple F F F F T T F
{'a': 1} dict F F F F T F T
Dog()(自作クラス) Dog F F F F F F F
OrderedDict() OrderedDict F F F F T F T
Decimal('1') Decimal F F F T F F F
np.int64(1) int64 F F F T F F F
np.float64(1) float64 F F T T F F F
np.array([1]) ndarray F F F F T F F
Color.RED(IntEnum) Color F T T T F F F

太字のセルが、つまずきやすいところです。True は isinstance(True, int) が True になる、np.int64(1) は int ではない、文字列は Iterable であり Sequence でもある、NumPy 配列は Sequence ではない、の4点を押さえておくと、判定の書き間違いが大きく減ります。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Python型判定はisinstanceとtypeどちら?違いと使い分け早見表」

type と isinstance の違いは「継承を見るかどうか」

type は作ったクラスそのもの、isinstance は親クラスも認める

type(x) は、その値を作ったクラスを1つだけ返します。isinstance(x, C) は、x のクラスが C であるか、C を継承したクラスであれば True を返します。

class Animal: pass
class Dog(Animal): pass

d = Dog()
print(type(d))                    # 作ったクラス
print(type(d).__name__)           # クラス名の文字列
print(type(d) == Dog, type(d) == Animal)
print(isinstance(d, Dog), isinstance(d, Animal), isinstance(d, object))
print(type(d).__mro__)            # 継承の並び
<class '__main__.Dog'>
Dog
True False
True True True
(<class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>)

Dog は Animal を継承しているので、「Animal として扱えるか」という問いには isinstance(d, Animal) が True と答えます。一方 type(d) == Animal は False です。「この関数は Animal を受け取る」という書き方をした場合、サブクラスの Dog が渡されても動いてほしいことがほとんどなので、判定には isinstance が合います。

isinstance が見ているのは __mro__(メソッド解決順序。そのクラスと親クラスを順に並べたもの)です。この並びのどこかに指定した型があれば True になります。

判断表:どちらを使うか

場面 選ぶもの 理由
引数の型で処理を分ける isinstance サブクラスが渡されても同じ分岐に入る
受け取った値が想定の型か確かめて例外を出す isinstance 同上
型名をログやエラーメッセージに出す type(x).__name__ 名前を取り出す用途
bool を整数扱いしたくない type(x) is int、または isinstance(x, int) and not isinstance(x, bool) bool は int のサブクラスのため
シリアライズなどで型ごとに厳密に書式を変える type(x) is 型 サブクラスを別扱いにしたい
2つの値が同じ型か比べる type(a) is type(b) 型同士の比較

type(x) == と type(x) is の違い

型はプログラムの中で1つしか存在しないオブジェクトなので、完全一致の判定は is で書けます。== はクラス(正確にはメタクラス)が __eq__ を定義していると結果が変わりうるため、完全一致を調べるなら is のほうが意図どおりになります。

class Meta(type):
    def __eq__(cls, other): return True   # 何と比べても等しいと答える
    def __hash__(cls): return 1
class Odd(metaclass=Meta): pass

print(type(Odd()) == int, type(Odd()) is int)
print(type(1) == int, type(1) is int)
True False
True True

通常のクラスでは == と is の結果は同じです。違いが出るのは上のような特殊なクラスだけですが、is は「同じオブジェクトか」を調べるだけなので速度面でも読みやすさの面でも素直です。静的解析ツール(Ruff や flake8 の E721)も、type(x) == int と書くと is か isinstance への書き換えを提案します。

bool は int のサブクラス:True が整数として通る

bool は int を継承して作られています。そのため isinstance(True, int) は True です。

print(isinstance(True, int), type(True) == int, True + True)
print(bool.__mro__)
print(issubclass(bool, int))
True False 2
(<class 'bool'>, <class 'int'>, <class 'object'>)
True

「数量は整数で受け取る」という関数に True が渡されると、isinstance(x, int) の検査を通り、1 として計算が進みます。bool を整数として受け取りたくないときは、先に bool を除きます。

def set_quantity(n):
    # 直す前: if not isinstance(n, int):
    if isinstance(n, bool) or not isinstance(n, int):
        raise TypeError(f"整数を渡してください: {type(n).__name__}")
    return n

print(set_quantity(3))
try:
    set_quantity(True)
except TypeError as e:
    print("TypeError:", e)
3
TypeError: 整数を渡してください: bool

type(n) is int と書いても bool を除けますが、その場合は IntEnum など int を継承したほかのクラスも除かれます。どこまで受け入れたいかで選びます。

None の判定は is None

None の型は NoneType で、3.10 以降は types.NoneType として参照できます。ただし判定は x is None と書くのが定番です。

import types
x = None
print(type(x), x is None)
print(isinstance(x, type(None)), isinstance(x, types.NoneType))
print(isinstance(x, int | None))     # 3.10 以降。Union の中では None と書ける
<class 'NoneType'> True
True True
True

None は1つしか存在しない値なので、is で比べるのが最も短く正確です。if not x: と書くと、0・空文字・空リストも同じ分岐に入るため、「None かどうか」を調べたいときは is None を使います。

複数の型をまとめて判定する(タプルと int | str)

isinstance の第2引数には、型のタプルを渡せます。Python 3.10 以降は int | str のように | でつないだ書き方も使えます。

print(isinstance(1, (int, str)))     # どのバージョンでも使える
print(isinstance(1, int | str))      # 3.10 以降
print(isinstance(1.5, int | str))
print(type(int | str))
True
True
False
<class 'types.UnionType'>

最後の行は Python 3.11 での表示です。Python 3.14 では <class 'typing.Union'> と表示されました。表示される型の名前が変わっただけで、判定の結果は同じです。

リストや文字列を渡すとエラーになります。複数指定はタプルか | で書きます。

isinstance(1, [int, str])
isinstance(1, "int")
TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union
書き方 使えるバージョン メモ
isinstance(x, (int, str)) すべて 入れ子のタプルも可
isinstance(x, int | str) 3.10 以降 型ヒントと同じ見た目で書ける
isinstance(x, typing.Union[int, str]) 3.10 以降 typing.Optional[int] も同様に True/False を返す
isinstance(x, [int, str]) 使えない TypeError になる

issubclass:クラス同士の親子関係を調べる

isinstance が「値とクラス」の関係を調べるのに対し、issubclass は「クラスとクラス」の関係を調べます。

print(issubclass(Dog, Animal), issubclass(bool, int))
print(issubclass(Dog, Dog))              # 自分自身も True
print(issubclass(int, (str, int)))       # タプルも渡せる
issubclass(Dog(), Animal)                # 値を渡すとエラー
True True
True
True
TypeError: issubclass() arg 1 must be a class

isinstance(x, C) は、おおよそ issubclass(type(x), C) と同じ意味です。クラスそのものを引数で受け取る関数(プラグインの登録、設定クラスの検査など)では issubclass を使います。

collections.abc で「性質」を判定する

「リストか」ではなく「ループで回せるか」「添字で取り出せるか」「辞書のように使えるか」を調べたいときは、collections.abc の抽象基底クラス(Abstract Base Class。特定のメソッドを持つことを表す型)を使います。

主な型の対応表(実行結果)

import collections.abc as abc
値の型 Iterable Iterator Sized Sequence MutableSequence Mapping Set Hashable
str T F T T F F F T
bytes T F T T F F F T
list T F T T T F F F
tuple T F T T F F F T
range T F T T F F F T
dict T F T F F T F F
set T F T F F F T F
ジェネレータ T T F F F F F T
dict_keys T F T F F F T F
np.ndarray T F T F F F F F
deque T F T T T F F F
抽象基底クラス 意味 判定の根拠
Iterable for で回せる __iter__ を持つ
Iterator next() で1つずつ取り出せる __iter__ と __next__ を持つ
Sized len() が使える __len__ を持つ
Sequence 順番があり添字で取り出せる 登録されたクラス、または継承したクラス
Mapping キーで値を引ける 同上
Callable 呼び出せる __call__ を持つ(callable(x) でも可)

文字列は Iterable であり Sequence でもあります。 「リストやタプルなら1件ずつ処理し、文字列なら1件として扱う」という分岐では、文字列を先に除く必要があります(後述の判定関数集に関数を用意しました)。

Iterable の判定は __iter__ の有無で決まる

Iterable は、クラスが継承していなくても __iter__ を持っていれば True になります。一方、__getitem__ だけで反復できるクラスは isinstance では False になります。

class MyIter:
    def __iter__(self): return iter([1])

class OldSeq:                      # __getitem__ だけを持つ
    def __getitem__(self, i):
        if i > 2: raise IndexError
        return i

print(isinstance(MyIter(), abc.Iterable))
print(isinstance(OldSeq(), abc.Iterable), list(OldSeq()))
True
False [0, 1, 2]

OldSeq は list() に渡すと反復できますが、isinstance(..., Iterable) は False です。反復できるかを確実に知るには iter(obj) を実際に呼んでみる方法があります。この点は「ダックタイピング」の節で扱います。

numbers.Number で数値かどうかを判定する

int と float だけなら isinstance(x, (int, float)) で足りますが、Decimal、Fraction、NumPy の数値まで含めて「数値か」を調べるなら numbers モジュールが便利です。

値 Number Real Integral isinstance(x, int) isinstance(x, float)
1 T T T T F
True T T T T F
1.5 T T F F T
1+2j T F F F F
Fraction(1, 2) T T F F F
Decimal('1.5') T F F F F
np.int64(1) T T T F F
np.float32(1) T T F F F
'1' F F F F F
  • numbers.Number:数値全般(複素数も含む)
  • numbers.Real:実数。大小比較や四捨五入ができる数値
  • numbers.Integral:整数

Decimal は Number ですが Real ではありません。 float と混ぜた計算ができない設計のため、実数の階層には登録されていません。Decimal も受け入れたい場合は isinstance(x, (numbers.Real, Decimal)) と明示します。

NumPy の型を判定する

NumPy の配列から取り出した1要素は、Python の int ではなく np.int64 などの NumPy スカラーです。

import numpy as np
a = np.array([1, 2, 3]); f = np.array([1.5])

print(type(a), a.dtype, type(a[0]))
print(isinstance(a[0], int), isinstance(a[0], np.integer))
print(isinstance(f[0], float), isinstance(f[0], np.floating), isinstance(np.float32(1), float))
print(np.issubdtype(a.dtype, np.integer), np.issubdtype(f.dtype, np.floating), np.issubdtype(a.dtype, np.number))
print(isinstance(np.bool_(True), bool), isinstance(np.str_('a'), str))
print(type(a.tolist()[0]), type(a[0].item()))
<class 'numpy.ndarray'> int64 <class 'numpy.int64'>
False True
True True False
True True True
False True
<class 'int'> <class 'int'>
調べたいこと 書き方
配列か isinstance(x, np.ndarray)
NumPy の整数スカラーか isinstance(x, np.integer)
NumPy の浮動小数点スカラーか isinstance(x, np.floating)
配列の要素型が整数か np.issubdtype(arr.dtype, np.integer)
Python の数値と NumPy の数値をまとめて isinstance(x, numbers.Number)
Python の型に戻したい x.item() / arr.tolist()

np.float64 は Python の float を継承しているので isinstance(x, float) が True ですが、np.float32 と np.int64 は継承していません。NumPy の値が混ざる可能性があるなら、numbers.Integral や numbers.Real で判定するか、.item() で Python の型に戻してから扱うと統一できます。 JSON に書き出すときに np.int64 がそのままでは変換できない、という場面でも .item() や .tolist() が役立ちます。

match 文のクラスパターンで型ごとに分岐する

Python 3.10 以降では、match 文の case int(): という書き方(クラスパターン)で型による分岐を書けます。内部では isinstance と同じ判定が行われます。

def describe(x):
    match x:
        case bool():                     # int より先に書く
            return "bool"
        case int() | float():
            return "数値"
        case str() as s:
            return f"文字列({len(s)}文字)"
        case [int(), int()]:
            return "intが2つのシーケンス"
        case list() | tuple():
            return "リストかタプル"
        case {"id": int(i)}:
            return f"idつきの辞書 id={i}"
        case Dog():
            return "Dog"
        case None:
            return "None"
        case _:
            return "その他"

for v in [True, 1, 1.5, "abc", [1, 2], [1, "a"], (1, 2, 3), {"id": 7, "x": 1}, None, {1}]:
    print(repr(v), "->", describe(v))
True -> bool
1 -> 数値
1.5 -> 数値
'abc' -> 文字列(3文字)
[1, 2] -> intが2つのシーケンス
[1, 'a'] -> リストかタプル
(1, 2, 3) -> リストかタプル
{'id': 7, 'x': 1} -> idつきの辞書 id=7
None -> None
{1} -> その他

押さえておきたい点は3つです。

  • case int(): のかっこは必須です。 case int: と書くと「何にでも一致して int という名前の変数に代入する」という意味になります。
  • case bool(): は case int(): より先に書きます。 順番を逆にすると、True は先にある int() に一致します(下の実行結果)。
  • case [int(), int()] のようなシーケンスパターンは、リストとタプルに一致し、文字列には一致しません。文字列を誤って1文字ずつ分解する心配がありません。
def m2(x):
    match x:
        case int(): return "int"
        case bool(): return "bool"
print(m2(True))
int

if isinstance(...) / elif isinstance(...) を3つ以上並べる場面では、match に書き換えると「型の判定」と「中身の取り出し」を1行で書けて見通しがよくなります。

コピペできる判定関数集

よく必要になる判定を関数にまとめました。import も含めてそのまま貼り付けて使えます。

import collections.abc as abc
import numbers


def is_number(x, *, allow_bool=False):
    """数値か(int / float / complex / Decimal / Fraction / NumPy の数値)。bool は既定で除く"""
    if isinstance(x, bool):
        return allow_bool
    return isinstance(x, numbers.Number)


def is_real_number(x):
    """大小比較できる実数か(bool・複素数・Decimal は除く)"""
    return isinstance(x, numbers.Real) and not isinstance(x, bool)


def is_iterable_not_str(x):
    """文字列・バイト列を除いた、for で回せるものか"""
    return isinstance(x, abc.Iterable) and not isinstance(x, (str, bytes, bytearray))


def is_list_like(x):
    """リストのように順番と添字を持つか(list / tuple / range / deque など。文字列は除く)"""
    return isinstance(x, abc.Sequence) and not isinstance(x, (str, bytes, bytearray))


def is_int_string(s):
    """整数として解釈できる文字列か"""
    if not isinstance(s, str):
        return False
    try:
        int(s)
    except ValueError:
        return False
    return True


def is_float_string(s):
    """小数として解釈できる文字列か"""
    if not isinstance(s, str):
        return False
    try:
        float(s)
    except ValueError:
        return False
    return True


def ensure_list(x):
    """None は空リスト、単独の値は1要素のリスト、反復できるものはリストにそろえる"""
    if x is None:
        return []
    if is_iterable_not_str(x):
        return list(x)
    return [x]

実行して確かめた結果です。

関数 入力 結果
is_number 1, 1.5, True, "1", Decimal("1"), np.int64(1), None T, T, F, F, T, T, F
is_real_number 1, 1.5, True, 1+2j, Fraction(1, 2), Decimal("1") T, T, F, F, T, F
is_iterable_not_str [1], (1,), {1}, {"a": 1}, range(3), "abc", b"ab", 1, None, np.array([1]) T, T, T, T, T, F, F, F, F, T
is_list_like [1], (1,), range(3), {1}, {"a": 1}, "abc", np.array([1]), deque() T, T, T, F, F, F, F, T
is_int_string "12", "-3", " 7 ", "12", "1_000", "1.5", "abc", "", 12, "0x1f" T, T, T, T, T, F, F, F, F, F
is_float_string "1.5", "1e3", "nan", "inf", "abc", "1,000" T, T, T, T, F, F
ensure_list None, "abc", (1, 2), 5 [], ['abc'], [1, 2], [5]

「整数として解釈できる文字列か」に str.isdigit を使うときの注意

str.isdigit() は手軽ですが、int() が受け付ける範囲と一致しません。

文字列 int(s) できるか s.isdigit()
"12" できる True
"-3" できる False
" 7 "(前後に空白) できる False
"12"(全角数字) できる True
"1_000" できる False
"²"(上付きの2) できない True
int("²")
ValueError: invalid literal for int() with base 10: '²'

「int() に渡せるか」を知りたいなら、実際に int() を呼んで ValueError を捕まえる is_int_string の形が最も正確です。 半角数字だけを受け付けたい入力欄なら、正規表現 re.fullmatch(r"-?[0-9]+", s) のように受け付ける範囲を明示します。is_float_string は "nan" や "inf" も True になるので、受け付けたくない場合は math.isfinite(float(s)) を追加します。

型ヒントは実行時チェックではない

型ヒント(def add(a: int, b: int) -> int のような注釈)は、エディタや mypy・Pyright といった型チェッカーが読むための情報で、Python 本体は実行時に検査しません。

def add(a: int, b: int) -> int:
    return a + b

print(add("1", "2"))
print(add.__annotations__)

from dataclasses import dataclass
@dataclass
class P:
    x: int
print(P("abc"))
12
{'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}
P(x='abc')

int と注釈した引数に文字列を渡しても、そのまま文字列の連結として実行されます。dataclass も同じで、注釈と異なる型の値をそのまま受け取ります。実行時に型を保証したい入り口(外部から届いた JSON、設定ファイル、ユーザー入力)では、isinstance による検査や、検証用ライブラリを別に用意します。 型ヒントの書き方そのものは、別記事「Pythonの型ヒントの書き方|3.12以降の新しい書き方まで」で扱っています。

list[int] を isinstance に渡すと TypeError になる

型ヒントで使う list[int] や dict[str, int] を、そのまま isinstance に渡すことはできません。

式 結果
isinstance([1, 2], list[int]) TypeError: isinstance() argument 2 cannot be a parameterized generic
isinstance({'a': 1}, dict[str, int]) TypeError: isinstance() argument 2 cannot be a parameterized generic
isinstance([1, 2], typing.List[int]) TypeError: Subscripted generics cannot be used with class and instance checks
isinstance('a', typing.Literal['a']) TypeError: Subscripted generics cannot be used with class and instance checks
isinstance(1, typing.Any) TypeError: typing.Any cannot be used with isinstance()
isinstance([1, 2], typing.List) True(添字なしなら動く)
isinstance(1, typing.Union[int, str]) True
isinstance(1, typing.Optional[int]) True

isinstance が調べるのは「入れ物の型」までで、要素の型までは見ません。要素の型も確かめたいときは、入れ物と中身を分けて書きます。

def is_list_of_int(x):
    return isinstance(x, list) and all(type(v) is int for v in x)

print(is_list_of_int([1, 2]), is_list_of_int([1, "a"]), is_list_of_int([True]))
True False False

type(v) is int としているのは、True を整数として数えないためです。bool も整数として認めるなら isinstance(v, int) にします。

ダックタイピングと try/except:型を調べずに使ってみる

Python には「必要な操作ができるなら、型は問わない」という考え方(ダックタイピング)があります。事前に型を調べる代わりに、使ってみて、できなかったら例外で受け止める書き方です。

def total_len(x):
    try:
        return len(x)
    except TypeError as e:
        return f"TypeError: {e}"

print(total_len([1, 2]), total_len("abc"), total_len(5))

try:
    iter(5)
except TypeError as e:
    print("TypeError:", e)

print(hasattr([], "__iter__"), hasattr(5, "__iter__"), callable(len), callable(1))
2 3 TypeError: object of type 'int' has no len()
TypeError: 'int' object is not iterable
True False True False
方法 向いている場面 気をつける点
isinstance(x, 型) 型ごとに処理の内容が変わる。入り口で早めに知らせたい 想定外の互換クラスを締め出すことがある
isinstance(x, abc.Iterable) など 「性質」で分けたい 文字列も Iterable
try / except 操作できるかだけが重要 except の範囲を狭く保つ(処理の中の別の TypeError も拾うため)
hasattr(x, "close") 特定のメソッドの有無を見たい 属性があっても呼び出せるとは限らない
callable(x) 関数として呼べるか クラスも True になる

型を調べる書き方と、使ってみる書き方は、どちらか一方に決めるものではありません。外部から入ってくるデータの入り口では isinstance で早めに確認し、内部の関数同士では型ヒントとダックタイピングに任せる、という組み合わせが読みやすく保ちやすい形です。

Protocol と runtime_checkable:メソッドの有無で isinstance する

typing.Protocol は「このメソッドを持っていれば、この型として扱う」という約束を型ヒントで表す仕組みです。そのままでは isinstance に渡せませんが、@runtime_checkable を付けると実行時の判定にも使えます。

from typing import Protocol, runtime_checkable

class Closable(Protocol):
    def close(self) -> None: ...

@runtime_checkable
class Closable2(Protocol):
    def close(self) -> None: ...

class Res:
    def close(self): return 1
class Bad:
    close = 5            # メソッドではなくただの値

try:
    isinstance(Res(), Closable)
except TypeError as e:
    print("TypeError:", e)

print(isinstance(Res(), Closable2), isinstance(1, Closable2), isinstance(Bad(), Closable2))
TypeError: Instance and class checks can only be used with @runtime_checkable protocols
True False True

Bad は close がメソッドではなく数値ですが、True になっています。runtime_checkable の判定は「その名前の属性があるか」だけを見ており、引数や戻り値の型までは確かめません。 細かい検査は型チェッカーに任せ、実行時の isinstance は大まかな確認として使うのが合っています。Protocol と抽象クラスの選び方は、別記事「Python 抽象クラスとProtocol|ABCとの違い・使い分け早見表」で詳しく扱っています。

判定の速度を測る

500万回の判定にかかった時間を timeit で測りました(Python 3.11.15、この記事の検証用コンテナでの値。環境で変わります)。

式 500万回の所要時間
type(x) is int 0.085 秒
isinstance(x, int) 0.082 秒
isinstance(x, (str, float, int)) 0.361 秒
isinstance(x, collections.abc.Iterable) 0.485 秒

type(x) is int と isinstance(x, int) はほぼ同じ速さです。タプルや抽象基底クラスは少し時間がかかりますが、1回あたり 0.1 マイクロ秒未満です。速度を理由に type を選ぶ必要はなく、意味(サブクラスを含めるかどうか)で選んで問題ありません。

つまずきやすい点のチェックリスト

症状 原因 直し方
True が整数として通る bool は int のサブクラス isinstance(x, bool) を先に除く
文字列が1文字ずつ処理される str は Iterable かつ Sequence is_iterable_not_str のように文字列を除く
NumPy の値が isinstance(x, int) で False np.int64 は int を継承していない numbers.Integral か np.integer で判定
isinstance(x, list[int]) で TypeError 添字つきの型は渡せない isinstance(x, list) と要素の検査を分ける
isinstance(x, [int, str]) で TypeError リストは渡せない タプル (int, str) か int | str
case int: が何にでも一致する かっこがないと変数への代入になる case int(): と書く
サブクラスを渡すと type(x) == 親 が False type は完全一致 isinstance を使う
型ヒントを書いたのに別の型が通る 型ヒントは実行時に検査されない 入り口で isinstance を使う
Decimal が numbers.Real で False Decimal は Real に登録されていない (numbers.Real, Decimal) と明示

よくある質問

Q. 結局、isinstance と type のどちらを使えばよいですか? A. 判定には isinstance を使います。サブクラスも同じ型として扱えるので、あとからクラスを継承で拡張しても分岐が保たれます。type は、型名を表示したいとき(type(x).__name__)と、サブクラスを含めず完全一致で調べたいとき(type(x) is int)に使います。

Q. 変数の型を確認するだけなら何を書けばよいですか? A. print(type(x)) で <class 'int'> のように表示されます。クラス名だけが欲しいときは type(x).__name__ です。NumPy 配列なら arr.dtype、pandas の DataFrame なら df.dtypes で要素の型を確認できます(pandas は今回の検証対象外で、一般に知られた使い方です)。

Q. isinstance(x, int | str) はどのバージョンから使えますか? A. Python 3.10 以降です。3.9 以前でも動かす必要があるなら、タプルの isinstance(x, (int, str)) を使います。結果は同じです。

Q. リストの中身がすべて int かどうかを isinstance で調べられますか? A. isinstance(x, list[int]) は TypeError になります。isinstance(x, list) and all(isinstance(v, int) for v in x) のように、入れ物と中身を分けて書きます。データの構造が複雑な場合は、検証用のライブラリを使うと定義をまとめて書けます。

まとめ

  • 型の判定は isinstance(x, 型) が基本。サブクラスも True になる
  • type(x) is 型 は完全一致を調べたいときだけ使う。型名の表示は type(x).__name__
  • bool は int のサブクラス。整数だけを受け取りたいときは bool を先に除く
  • 複数の型はタプル (int, str) か、3.10 以降の int | str で指定する
  • 「回せるか」「数値か」は collections.abc と numbers で判定する。文字列が Iterable である点と、NumPy の整数が int ではない点に注意
  • 型ヒントは実行時に検査されない。list[int] を isinstance に渡すと TypeError になる
  • 型ごとの分岐が増えたら match 文のクラスパターンが読みやすい

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Python型判定はisinstanceとtypeどちら?違いと使い分け早見表」

株式会社RJCでは、Pythonの型判定の使い分けを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?