在 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))) # True2. 常见内置类型的判断
# 数字
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 # True3. 使用 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)) # True4. 函数、可调用对象、模块、类与实例
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.Coroutine6. 序列、映射、集合等抽象基类
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)) # True7. 检查自定义类型及泛型(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 函数是一个整合示例,你可以根据实际需求裁剪或扩展。