在 Python 面向对象的世界里,自省(Introspection) 是一项极具魅力的核心能力 —— 它让我们能在程序运行时,主动探查对象的类型、属性、方法与内部结构,就像拥有一双 “透视眼”,穿透封装,看清对象的本质。
今天,我们就聚焦 Python 自省最常用的两大神兵:__dict__**** 属性 与 dir()** 内置函数**,从继承案例入手,彻底搞懂它们的用法、区别与底层逻辑✨。
Bilibili 同步视频
一、先搭舞台:一个简单的继承示例
为了清晰演示自省机制,我们先定义一组具有继承关系的类,这是后续所有操作的基础👇
# 定义父类 Person
class Person:
"""人:基础父类"""
name = "user" # 类属性
# 定义子类 Student,继承自 Person
class Student(Person):
"""学生:继承 Person,扩展自有属性"""
def __init__(self):
self.school_name = "慕课网" # 实例属性
# 实例化 Student 对象
user = Student()
这里的层级关系很清晰:
Student → 继承 Person → 实例化为 user,Person 的类属性 name 与 Student 的实例属性 school_name 共同构成了对象的属性体系。
二、__dict__:对象属性的 “存储字典”
1. 底层核心:高性能的内置数据结构
在 CPython 编译器 中,__dict__ 是纯 C 语言实现的字典,经过了极致优化,是 Python 性能最高的数据结构之一🔥。
Python 类与实例的所有属性,本质上都通过 __dict__ 来存储和管理 —— 它就是对象属性的 “专属账本”。
2. 实例的 __dict__:只存自身实例属性
直接打印实例 user 的 __dict__,我们会发现:
print(user.__dict__)
# 输出:{'school_name': '慕课网'}
它只包含实例自身初始化的属性,并没有父类 Person 的 name 属性!
但神奇的是,直接访问 user.name 依然能得到结果:
print(user.name) # 输出:user
这是 Python 的 MRO(方法解析顺序) 在起作用:访问属性时,Python 会沿继承链向上查找,name 是父类 Person 的类属性,不属于子类实例,因此不会出现在实例的 __dict__ 中。
3. 类的 __dict__:包含完整类信息
类本身也是对象,它的 __dict__ 远比实例丰富,包含模块、类名、文档、弱引用、类属性等全部信息:
print(Person.__dict__)
输出会包含:
__module__(所属模块)、name(类属性)、__doc__(类文档)、__dict__(自身引用)、__weakref__(弱引用)等完整元信息。
4. 动态操控:直接修改 __dict__ 增删属性
__dict__ 不仅能查看,还能直接读写,实现对象属性的动态操控:
# 动态添加实例属性
user.__dict__["school_addr"] = "北京市"
# 直接访问新属性
print(user.school_addr) # 输出:北京市
这就是 __dict__ 的强大之处 —— 直接操作对象的属性存储字典,灵活掌控对象状态。
三、dir():对象全貌的 “属性清单”
如果说 __dict__ 是属性账本,那 dir() 就是全量目录📋。
dir() 是 Python 内置的自省函数,功能比 __dict__ 更强大,能列出对象所有可用属性与方法(含继承的、内置的魔法方法)。
1. 核心用法:一键获取全量属性
# 查看 Student 实例的所有属性
print(dir(user))
执行后会输出一长串列表,不仅有 school_name、name,还有 Python 内置的 __init__、__str__、__class__ 等魔法方法,覆盖对象的全部可用成员。
2. dir() 与 __dict__ 的关键区别
| 特性 | __dict__ | dir() |
|---|---|---|
| 内容 | 仅对象自身存储的属性 + 对应值 | 对象所有可用属性 / 方法名(含继承、内置) |
| 格式 | 字典(键值对) | 列表(仅名称) |
| 适用场景 | 查看 / 修改自有属性、动态操控 | 快速探查对象全貌、确认支持的方法 |
3. 兼容无 __dict__ 的内置对象
很多 Python 内置类型(如 list、str)没有 ****__dict__,直接访问会抛异常,但 dir() 依然能完美工作:
a = [1, 2, 3]
# print(a.__dict__) # 报错:AttributeError
print(dir(a)) # 正常输出 list 的所有方法与属性
这让 dir() 成为探查所有 Python 对象的通用工具,尤其适合查看内置类型实现的魔法函数。
四、总结:用好自省,吃透 Python 对象
-
自省是什么:运行时探查对象内部结构的能力,是 Python 动态语言的核心特性;
-
__dict__:C 语言实现的高性能属性字典,存自身属性 + 值,支持动态操控,类与实例都有; -
dir():全量属性清单,列所有可用成员,无值、兼容所有对象,适合快速探查; -
属性查找:实例无属性时,Python 会通过 MRO 沿继承链向上查找,父类属性不属于实例本身。
掌握 __dict__ 与 dir(),就等于掌握了 Python 对象的透视密码,无论是调试、源码阅读还是动态编程,都能事半功倍🚀。
下一节,我们将继续探索 Python 面向对象的另一核心:super()**** 函数,彻底理清继承中的方法调用逻辑~