Python 检查对象类型的最佳方式是什么?
type(x) 返回精确类型,isinstance(x, cls) 支持继承判断且是推荐做法,isinstance 还支持元组多类型检查。本文对比 type、isinstance 与鸭子类型的选择。
结论先行:大多数情况下用 isinstance(obj, 类型)——它能正确识别子类实例,语义符合直觉;type(obj) is 类型 只在需要精确匹配、排除子类时使用;更 Pythonic 的做法是"鸭子类型":不查类型,直接调用方法并用 try/except 兜底。
type():精确类型
x = 5
print(type(x)) # <class 'int'>
type(x) is int # True
type(True) is int # False(bool 是 int 的子类,但精确类型不同)
注意最后一个例子:type() 做精确比较时会"漏掉"子类,这通常不是调用方想要的。
isinstance():推荐的通用方式
class A: pass
class B(A): pass
isinstance(B(), A) # True,子类实例也算
isinstance(True, int) # True,bool 继承自 int
# 支持类型元组,一次查多种
isinstance(x, (int, float))
isinstance 遵循继承体系,对框架扩展、抽象基类(如 collections.abc.Iterable)判断都更友好。
鸭子类型:能不查就不查
Python 社区更推崇"看到鸟走起来像鸭子、叫起来像鸭子,那它就是鸭子":
def process(items):
for it in items: # 不关心是不是 list,能迭代就行
...
需要特定方法时,要么直接调用并捕获 AttributeError(EAFP 风格),要么用 hasattr(obj, 'read') 粗判,而不是锁死具体类型。
观测云对照
解析日志字段时用 isinstance 防御脏数据。 写 Pipeline 前置清洗脚本或自定义处理逻辑时,同一个字段可能时而字符串时而数字,先用 isinstance(v, (int, float)) 分流再转换,避免脏数据把整条链路打挂;进入观测云后还可用 Pipeline 的类型转换函数统一字段类型。
常见问题(FAQ)
Q:为什么 isinstance(True, int) 是 True?
A:Python 里 bool 是 int 的子类,True == 1。要排除布尔值需额外判断 not isinstance(x, bool)。
Q:判断 None 用什么?
A:用 x is None,不要用 type 或 isinstance,单例比较用 is 最快也最规范。
Q:抽象基类能用 isinstance 吗?
A:可以,isinstance(x, collections.abc.Mapping) 能匹配所有映射类型(dict、OrderedDict 等),是检查"能力"而非"血统"的好方法。