dir() 不显示父类私有成员,因其仅列出当前对象可访问的名称,不递归继承链,且python名称改写(如__value→_classname__value)后的私有成员不会被自动还原或展示。

dir() 为什么看不到父类的私有方法和属性?
dir() 默认只列出当前对象「可访问」的名称,不递归展开继承链中被名称改写(name mangling)的私有成员。Python 中以双下划线开头且不以双下划线结尾的名称(如 <strong>init</strong>、__value)在类定义时会被自动重命名为 _ClassName<strong>value</strong> 形式,而 dir() 不会主动还原或展示这些改写后的名称——除非它们确实存在于当前类的 dict__ 或其 MRO 中显式定义的位置。
- 父类的
__method在子类未调用或未继承覆盖时,不会出现在子类实例的dir()结果里 - 即使子类继承了父类的
<strong>init</strong>,只要没显式定义或通过super()触发,dir()也可能不把它列出来(取决于解释器版本和实现细节) -
dir()的行为依赖于对象的<strong>dir</strong>()方法;若未自定义,就按默认逻辑查<strong>dict</strong>、类型 MRO 和基础类型属性
如何看到完整的继承成员(包括父类的公有/受保护成员)?
想绕过 dir() 的“过滤”倾向,得手动遍历 MRO 并合并属性:
- 用
inspect.getmembers(obj)配合lambda x: not x.startswith('_')可筛出非私有成员,但它仍不会显示被 name mangling 的项 - 更可靠的是:遍历
type(obj).<strong>mro</strong>,对每个类调用dir(cls),再去重合并(注意顺序,靠前的类优先) - 如果目标是调试继承结构,直接查
obj.<strong>class</strong>.<strong>mro</strong>比依赖dir()更准确
例如,检查一个子类实例 inst 的全部可调用方法:
import inspect
all_methods = {
name for cls in type(inst).__mro__
for name, value in inspect.getmembers(cls, predicate=inspect.isfunction)
if not name.startswith('_') or name in ('__init__', '__str__')
}
为什么 dir(list) 显示 __add__,但 dir(mylist_subclass) 却没有?
这不是 bug,而是因为 dir() 对内置类型(如 list)和用户自定义类的处理逻辑不同:内置类型的 C 实现把很多特殊方法注册在类型对象上,而用户类的 <strong>add</strong> 若未显式定义,就不会进入其 <strong>dict</strong>,也不会被 dir() 自动推导。
- 子类未重写
<strong>add</strong>时,它实际继承自list,但该方法不在子类自己的命名空间里 -
dir()默认不向上搜索整个 MRO 查找未被“本地化”的特殊方法 - 解决办法:显式在子类中写
<strong>add</strong> = list.<strong>add</strong>,或用help(mylist_subclass)查继承关系
真正影响调试的其实是 __dir__ 的自定义覆盖
很多框架(如 Django model、attrs、dataclasses)会重写 <strong>dir</strong>() 来隐藏内部字段或注入动态属性。一旦类定义了它,dir() 就完全听它的返回值,不再走默认逻辑。
- 检查
hasattr(cls, '<strong>dir</strong>')能快速判断是否被干预 - 若需原始行为,可临时删掉:
delattr(cls, '<strong>dir</strong>')(仅限调试,别在线上干这事) - 第三方库常借此控制 IDE 补全提示的内容,所以你看到的“不完整”,往往是设计使然,不是缺陷
Python 的 dir() 本质是个调试辅助工具,不是反射权威入口;它省略什么、包含什么,取决于你是否触发了 name mangling、是否自定义了 <strong>dir</strong>、以及目标类是否为内置类型——这些细节叠加起来,就让“为什么看不到”变得特别容易误判。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











