dir()返回对象可访问名,本质调用__dir__()方法,默认合并实例__dict__、类及父类属性、协议方法;__dict__仅存实例显式赋值属性,不包含类属性、方法或__slots__类的属性。

dir() 返回的是“可访问名”,不是“已赋值属性”
它本质是调用对象的 __dir__() 方法(可被重写),默认会合并三类来源:实例 __dict__、类及其父类的 __dict__、协议方法(如 __len__、__str__)和特殊属性。所以 dir(obj) 里能看到 append(来自 list 类)、data1(实例刚赋的)、__init__(继承自 object),哪怕你从没手动定义过它们。
常见错误现象:dir(obj) 列出一堆双下划线开头的项,误以为都是“当前对象的属性”;其实多数是 Python 内部协议钩子,跟业务逻辑无关。
使用场景:
- 交互式调试时快速看“这个对象能点出什么”(比如 IPython Tab 补全就靠它)
- 检查模块公开了哪些接口:
dir(json) - 但不能用来判断“这个字段是不是我代码里显式设置的”
__dict__ 只存“实例自己挂上去的键值对”
__dict__ 是个字典,只记录该实例通过 self.xxx = ... 显式赋值过的属性,不包含:
- 类属性(如
class A: x = 1) - 方法、
@property、描述符 - 父类继承来的任何东西
- 用了
__slots__的类——直接没有__dict__属性
示例:
class Person:
species = "Homo sapiens"
def __init__(self, name):
self.name = name
@property
def greeting(self):
return f"Hi, {self.name}"
<p>p = Person("Alice")
print(p.<strong>dict</strong>) # {'name': 'Alice'}
print(dir(p)) # 包含 'name', 'greeting', 'species', '<strong>init</strong>', '<strong>dict</strong>', ...</p>
注意:greeting 在 dir(p) 里可见,但不在 p.__dict__ 中;species 是类属性,也不在 p.__dict__ 里。
为什么有些对象根本没 __dict__?
不是所有 Python 对象都支持动态属性绑定:
- 内置类型(
int、list、str)没有__dict__,调用会报AttributeError: '__dict__' attribute not found - 声明了
__slots__的类,实例会省掉__dict__以节省内存,比如class Point: __slots__ = ('x', 'y') - 某些 C 扩展对象(如 NumPy 数组)也可能不提供
__dict__
但 dir() 不受限制——它底层走的是对象的类型信息和继承链,所以对这些对象依然可用。
想准确知道“哪些字段是我代码里设的”?别只信 dir 或 __dict__
真正可靠的方案得组合判断:
- 先确认对象有没有
__dict__:hasattr(obj, '__dict__') - 再排除类属性:
set(obj.__dict__.keys()) - set(type(obj).__dict__.keys())(粗略,不处理继承) - 更健壮的做法是用
inspect.getmembers(obj, lambda x: not callable(x)),再过滤掉以双下划线开头的项
容易被忽略的一点:__dict__ 里的私有属性名会被自动改写(如 __secret → _ClassName__secret),而 dir() 显示的是改写后的名字——这会让两个结果看起来更不一致。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











