在 Python 中,判断变量数据类型主要有两种方式:type() 和 isinstance()。
下面给出全面的判断方法与代码示例,涵盖内置类型、抽象基类、数字类型、鸭子类型及一些特殊场景。


1. 基础判断:type() 与 isinstance() 的区别

x = 10
 
# type() 返回精确类型,不推荐用于类型检查(不支持继承)
print(type(x) == int)        # True
print(type(x) is int)        # True(更推荐用 is 比较)
 
# isinstance() 支持继承,是官方推荐的方式
print(isinstance(x, int))    # True
# 同时检查多个类型
print(isinstance(x, (int, float)))  # True

2. 常见内置类型的判断

# 数字
isinstance(1, int)           # True
isinstance(1.0, float)       # True
isinstance(1+2j, complex)    # True
# 布尔(注意:bool 是 int 的子类)
isinstance(True, bool)       # True
isinstance(True, int)        # True  ← 需要先判断 bool 避免混淆
 
# 字符串与字节
isinstance("hello", str)      # True
isinstance(b"hello", bytes)   # True
isinstance(bytearray(5), bytearray)  # True
 
# 容器
isinstance([1,2], list)       # True
isinstance((1,2), tuple)      # True
isinstance(range(5), range)   # True
isinstance({"a":1}, dict)     # True
isinstance({1,2}, set)        # True
isinstance(frozenset({1,2}), frozenset)  # True
 
# None 类型
isinstance(None, type(None))  # True
# 更直接
x = None
x is None                     # True

3. 使用 numbers 模块检查抽象数字类型

import numbers
 
# numbers.Number 包含所有数字类型(int, float, complex, Fraction, Decimal)
print(isinstance(1, numbers.Number))      # True
print(isinstance(1.0, numbers.Real))      # True
print(isinstance(1+2j, numbers.Complex))  # True
print(isinstance(1, numbers.Integral))    # True
# 不包括 bool?bool 是 Integral 的子类,所以也返回 True
print(isinstance(True, numbers.Integral)) # True

4. 函数、可调用对象、模块、类与实例

def func(): pass
class MyClass: pass
obj = MyClass()
 
# 函数
import types
isinstance(func, types.FunctionType)          # True
# 内置函数
isinstance(len, types.BuiltinFunctionType)    # True
# lambda
isinstance(lambda x: x, types.LambdaType)     # True
 
# 可调用对象(更通用的检测方式)
callable(func)       # True
callable(MyClass)    # True(类是可调用的)
callable(obj)        # False,除非定义了 __call__
 
# 模块
import os
isinstance(os, types.ModuleType)              # True
 
# 类与实例
isinstance(MyClass, type)                     # True(类本身是 type 的实例)
isinstance(obj, MyClass)                      # True
isinstance(obj, object)                       # True(所有类最终继承 object)

5. 迭代器、生成器与可迭代对象(鸭子类型检查)

from collections.abc import Iterable, Iterator, Generator
 
# 可迭代对象(有 __iter__ 或 __getitem__)
print(isinstance([1,2], Iterable))    # True
print(isinstance(123, Iterable))      # False
 
# 迭代器(有 __next__ 和 __iter__)
it = iter([1,2])
print(isinstance(it, Iterator))       # True
 
# 生成器(迭代器的一种)
gen = (x*2 for x in range(3))
print(isinstance(gen, Generator))     # True
 
# 协程?可用 collections.abc.Coroutine

6. 序列、映射、集合等抽象基类

from collections.abc import Sequence, MutableSequence, Mapping, Set
 
# 序列(支持索引和长度):list, tuple, range, str, bytes...
print(isinstance([1,2], Sequence))          # True
print(isinstance("abc", Sequence))          # True
print(isinstance({1,2}, Sequence))          # False
 
# 可变序列
print(isinstance([1,2], MutableSequence))   # True
print(isinstance((1,2), MutableSequence))   # False
 
# 映射(dict 类)
print(isinstance({"a":1}, Mapping))         # True
 
# 集合
print(isinstance({1,2}, Set))               # True
print(isinstance(frozenset({1,2}), Set))    # True

7. 检查自定义类型及泛型(typing 运行时)

from typing import List, get_origin, get_args
 
# 简单的类型注解检查(仅限泛型擦除后的外层类型)
def check_list_of_ints(obj):
    # 运行时 List[int] 就是 list,无法保存参数 int
    return isinstance(obj, list) and all(isinstance(i, int) for i in obj)
 
# 使用 typing.get_origin 和 get_args 可对带泛型的变量进行结构检查
type_hint = List[int]
origin = get_origin(type_hint)      # <class 'list'>
args = get_args(type_hint)          # (<class 'int'>,)
# 然后进行递归验证(可自行扩展)

8. 实用函数:全面判断变量类型

下面提供一个“万能”函数,能识别 20+ 种常见类型并给出描述:

import types
import numbers
from collections.abc import Iterable, Iterator, Generator, Mapping, Set, Sequence
 
def describe_type(obj):
    """返回变量的详细类型信息"""
    # None
    if obj is None:
        return "NoneType"
 
    # 布尔(必须在 int 之前判断)
    if isinstance(obj, bool):
        return "bool"
 
    # 数字层次
    if isinstance(obj, numbers.Integral):
        return "int (or subclass, e.g., bool)"
    if isinstance(obj, numbers.Real):
        return "float"
    if isinstance(obj, numbers.Complex):
        return "complex"
    if isinstance(obj, numbers.Number):   # 其他数字如 Fraction, Decimal
        return "number (other)"
 
    # 字符串与字节
    if isinstance(obj, str):
        return "str"
    if isinstance(obj, bytes):
        return "bytes"
    if isinstance(obj, bytearray):
        return "bytearray"
 
    # 标准容器
    if isinstance(obj, list):
        return "list"
    if isinstance(obj, tuple):
        return "tuple"
    if isinstance(obj, range):
        return "range"
    if isinstance(obj, dict):
        return "dict"
    if isinstance(obj, set):
        return "set"
    if isinstance(obj, frozenset):
        return "frozenset"
 
    # 函数相关
    if isinstance(obj, types.BuiltinFunctionType):
        return "builtin_function"
    if isinstance(obj, types.FunctionType):
        return "function"
    if isinstance(obj, types.LambdaType):
        return "lambda"
    if isinstance(obj, types.MethodType):
        return "method"
    if callable(obj):
        return "callable (other)"
 
    # 模块
    if isinstance(obj, types.ModuleType):
        return "module"
 
    # 类与实例
    if isinstance(obj, type):
        return f"class '{obj.__name__}'"
    # 一般实例
    if hasattr(obj, '__class__'):
        return f"instance of '{obj.__class__.__name__}'"
 
    # 迭代器/生成器
    if isinstance(obj, Generator):
        return "generator"
    if isinstance(obj, Iterator):
        return "iterator"
    if isinstance(obj, Iterable):
        return "iterable"
 
    # 兜底
    return f"unknown type: {type(obj).__name__}"
 
 
# 测试
tests = [
    42, True, 3.14, 2+5j, "hello", b"data", None,
    [], (1,), range(3), {"a":1}, {1,2}, frozenset({3}),
    lambda x: x, sum, describe_type, os, describe_type.__class__
]
for t in tests:
    print(f"{str(t):<25} -> {describe_type(t)}")

9. 注意事项与最佳实践

注意点说明
优先使用 isinstance它支持继承,更符合面向对象思想;type() 不识别子类。
bool 是 int 的子类isinstance(True, int) 返回 True,判断时应先检查 bool。
鸭子类型很多时候不需要检查具体类型,只需检查是否实现了特定协议(如 callable、__iter__、__len__ 等)。使用 collections.abc 中的抽象基类可以做到这一点。
None 的判断直接用 is None 而不是 == None,更可靠。
自定义类isinstance(obj, MyClass) 或 isinstance(obj, MyBase),完全兼容。
泛型容器运行时 List[int] 被擦除成 list,内部元素类型需要手动遍历检查。

总结

全面的 Python 数据类型判断应综合利用 isinstance、抽象基类(collections.abc)、numbers 模块、types 模块以及鸭子类型检测函数(callable、hasattr 等)。上面的 describe_type 函数是一个整合示例,你可以根据实际需求裁剪或扩展。