重写 __dir__ 方法能让 ipython/jupyter 实现点号补全,但仅影响补全列表且需与 __getattr__ 配合才能避免运行时报错;ide 如 pycharm、pylance 通常忽略实例级 __dir__,依赖类型提示或类定义。

直接说结论:重写 __dir__ 方法确实能让 IDE 或 IPython 在点号补全(obj.)时显示你指定的属性名,但它只影响补全列表,不改变实际可访问性或属性存在性——补全项里写的字段,如果没真实定义,运行时仍会抛 AttributeError。
为什么 __dir__ 被调用但补全不生效?
常见错觉是改了 __dir__ 就能“让属性出现”,其实补全行为依赖两层:Python 运行时调用 __dir__ 获取候选名,但 IDE(如 PyCharm、VS Code 的 Pylance)往往缓存类型信息或绕过它,优先查类定义和 __annotations__。IPython 和 Jupyter 则较忠实执行 __dir__。
- PyCharm 默认忽略实例级
__dir__,需关闭 “Use __dir__ for completion” 选项(Settings → Editor → General → Code Completion)并重启 - VS Code + Pylance 基本不调用实例
__dir__,仅在无类型提示时 fallback 到它 - IPython/Jupyter 控制台中,只要返回字符串列表,补全立即生效
如何正确实现 __dir__ 返回动态字段?
重点不是“返回什么”,而是“返回哪些名字才合理”。它必须返回 str 列表,且名字应与实际支持的访问方式一致(比如有对应 @property、__getattr__ 或已赋值的实例变量)。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 不要返回纯虚构名(如
["fake_field"]),否则补全后obj.fake_field运行时报错 - 若字段由
__getattr__动态生成,__dir__应返回相同逻辑推导出的名字集合 - 建议合并父类
dir(self)结果,再增补自定义项,避免丢失内置方法:return list(set(dir(super()) + ["my_prop", "dynamic_key"])) - 避免在
__dir__中做耗时计算(如网络请求、文件扫描),补全触发频繁,会明显卡顿
__dir__ 和 __getattr__ 必须配对使用
这是最容易漏掉的约束:补全是“提示用户能输什么”,而 __getattr__ 是“告诉 Python 这些输入怎么响应”。两者脱节就会出现补全有、运行炸的情况。
class Config:
def __init__(self):
self._data = {"host": "localhost", "port": 8000}
<pre class="brush:python;toolbar:false;">def __dir__(self):
# 补全时显示所有 key
return list(self._data.keys()) + list(super().__dir__())
def __getattr__(self, name):
# 真正响应这些 key
if name in self._data:
return self._data[name]
raise AttributeError(f"{type(self).__name__} has no attribute '{name}'")
这样 cfg. 补全会出现 host 和 port,且 cfg.host 确实能取到值。但如果删掉 __getattr__,补全照常显示,运行就崩。
真正麻烦的是嵌套结构或带参数的“伪属性”——__dir__ 只能返回静态字符串,没法表达 get_user(id=123) 这种调用形式,这类场景补全意义有限,不如用文档字符串或类型提示替代。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










