获取对象信息与类属性
本教程共 70 篇 · 第 34 篇 · 更新于 2026-07-22 · 约 5 分钟阅读
34. 获取对象信息与类属性
本节目标:学会用
type()、isinstance()、dir()、hasattr()等工具检查对象,彻底分清实例属性和类属性的区别。
代码写多了,经常需要回答这些问题:这个对象是什么类型?它有哪些方法?某个属性存在吗?Python 提供了一系列内建函数,让你能在运行时「 introspect(内省)」对象。
type():查看对象类型
print(type(123)) # <class 'int'>
print(type('hello')) # <class 'str'>
print(type([])) # <class 'list'>
对于自定义类,同样适用:
class Dog:
pass
d = Dog()
print(type(d)) # <class '__main__.Dog'>
type() 返回的是对象的精确类型,不考虑继承关系。
isinstance():考虑继承链
上一章提过,isinstance 比 type 更宽松:
class Animal: pass
class Dog(Animal): pass
d = Dog()
print(isinstance(d, Dog)) # True
print(isinstance(d, Animal)) # True
print(type(d) == Animal) # False
isinstance 还可以同时检查多个类型:
print(isinstance(123, (int, str))) # True
print(isinstance([], (list, dict))) # True
第二个参数传元组,满足其一就返回 True。
Tip判断类型时,优先用
isinstance。type(x) == SomeClass在继承场景下会误判。
hasattr()、getattr()、setattr()
这三个函数用来动态操作对象的属性:
class Person:
def __init__(self, name):
self.name = name
p = Person('张三')
print(hasattr(p, 'name')) # True
print(hasattr(p, 'age')) # False
print(getattr(p, 'name')) # 张三
print(getattr(p, 'age', 0)) # 属性不存在时返回默认值 0
setattr(p, 'age', 25)
print(p.age) # 25
getattr 的第三个参数是默认值。如果不给,属性不存在时会抛 AttributeError。
这些函数在写框架、序列化库时特别常用。你不必提前知道对象有什么属性,运行时探测即可。
dir():列出对象的所有属性和方法
s = 'hello'
print(dir(s))
# ['__add__', '__class__', ... , 'upper', 'zfill']
dir() 返回一个字符串列表,包含对象的所有属性和方法名,包括双下划线的特殊方法。它非常适合在交互式环境里快速探索一个对象。
对于自己写的类,dir() 同样有效:
class Demo:
def __init__(self):
self.x = 1
def foo(self):
pass
d = Demo()
print(dir(d))
# ['__class__', ..., 'foo', 'x']
实例属性 vs 类属性:再深入
31 章简单提过类属性,这里彻底讲清楚。
查找顺序
当你访问 obj.attr 时,Python 按这个顺序查找:
- 先在实例
obj的__dict__里找 - 找不到,再去类
type(obj)的__dict__里找 - 还找不到,沿继承链向上找
class Counter:
count = 0
c = Counter()
print(c.count) # 0(实例里没有,去类里找)
c.count = 10
print(c.count) # 10(实例里有了,优先用实例的)
print(Counter.count) # 0(类属性本身没变)
c.count = 10 不是修改类属性,而是给实例 c 新建了一个同名属性。之后访问 c.count,实例属性会「遮挡」类属性。
用类属性做共享状态
类属性所有实例共享,适合放「全局计数器」之类的数据:
class ConnectionPool:
active_count = 0
def __init__(self):
ConnectionPool.active_count += 1
def close(self):
ConnectionPool.active_count -= 1
p1 = ConnectionPool()
p2 = ConnectionPool()
print(ConnectionPool.active_count) # 2
p1.close()
print(ConnectionPool.active_count) # 1
Warning对于可变对象(列表、字典),类属性作为共享状态时要特别小心:
class Bad: items = [] # 所有实例共享同一个列表! a = Bad() b = Bad() a.items.append(1) print(b.items) # [1] —— b 也被改了如果每个实例需要独立的数据,务必在
__init__里初始化:self.items = []。
用 __slots__ 节省内存(预告)
默认情况下,每个实例都有一个 __dict__ 字典来存属性,这很灵活,但内存开销大。如果你需要创建大量实例,可以用 __slots__ 限制属性名,从而省内存。
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
# p.z = 3 # AttributeError: 'Point' object has no attribute 'z'
__slots__ 会在第 35 章详细讲,这里先混个脸熟。
实战:写一个属性检查工具
把学到的内省函数串起来,写个小工具:
def inspect_obj(obj):
print(f"类型: {type(obj).__name__}")
print(f"属性列表:")
for name in dir(obj):
if not name.startswith('__'):
attr = getattr(obj, name)
kind = '方法' if callable(attr) else '属性'
print(f" - {name} ({kind})")
class Car:
wheels = 4
def __init__(self, brand):
self.brand = brand
def run(self):
print(f"{self.brand} 在行驶")
c = Car('比亚迪')
inspect_obj(c)
这个工具能自动列出对象的公开属性和方法,调试时很有用。
小结
type()看精确类型;isinstance()考虑继承,优先用它。hasattr()/getattr()/setattr()动态操作属性。dir()列出所有属性和方法,适合探索未知对象。- 实例属性存在
__dict__里,类属性存在类的__dict__里。 - 访问属性时,实例优先于类。修改实例属性不会触及类属性。
这些内省工具就像医生的听诊器,让你能「看见」代码内部的状态。写复杂系统时,它们是排查问题的利器。
来源:参考了 runoob「Python3 面向对象」、liaoxuefeng「获取对象信息」和「实例属性和类属性」、pythondoc「9. 类」等,改写后所得。