Python __dir__ 方法
最后修改于 2025 年 4 月 8 日
本综合指南探讨 Python 的 __dir__
方法,该特殊方法用于自定义属性列表。我们将介绍基本用法、自定义实现、继承行为和实际示例。
基本定义
__dir__
方法返回对象的有效属性列表。 它由内置的 dir()
函数调用,以获取对象的属性名称。
主要特征:它应该返回一个字符串列表,有助于内省,并且可以被重写以自定义属性可见性。 未定义时,Python 提供默认实现。
基本 __dir__ 实现
这是一个简单的类,实现了 __dir__
来演示其基本行为。 这展示了它如何与 dir()
函数交互。
class Person: def __init__(self, name, age): self.name = name self.age = age def __dir__(self): return ['name', 'age', 'greet'] def greet(self): return f"Hello, I'm {self.name}" p = Person("Alice", 30) print(dir(p)) # Shows ['age', 'greet', 'name']
此示例显示了一个自定义 __dir__
实现,该实现显式列出了可用的属性。 无论可能存在的其他属性如何,输出都与返回的列表匹配。
请注意,默认实现将包括更多属性,例如 __class__
和 __dict__
。 我们的自定义版本将可见性限制为仅指定的名称。
与默认属性结合
通常,您希望同时包含自定义属性和 Python 的默认属性。 此示例展示了如何将它们结合起来。
class Vehicle: def __init__(self, make, model): self.make = make self.model = model def __dir__(self): # Get default attributes default = super().__dir__() # Add our custom attributes custom = ['make', 'model', 'info'] return sorted(set(default + custom)) def info(self): return f"{self.make} {self.model}" v = Vehicle("Toyota", "Corolla") print(dir(v)) # Includes both default and custom attributes
此实现首先使用 super().__dir__()
获取默认属性,然后将它们与自定义属性结合。 set()
确保没有重复项,而 sorted()
提供一致的排序。
当您想要保持标准的 Python 行为,同时向列表中添加特定属性时,此模式非常有用。
动态属性列表
__dir__
可以根据对象状态或其他条件动态生成属性名称。 此示例显示了动态属性生成。
class Config: def __init__(self): self._settings = { 'debug': False, 'log_level': 'INFO', 'timeout': 30 } def __dir__(self): base = super().__dir__() settings = [f"get_{k}" for k in self._settings] settings += [f"set_{k}" for k in self._settings] return sorted(set(base + settings)) def __getattr__(self, name): if name.startswith('get_'): key = name[4:] return lambda: self._settings.get(key) elif name.startswith('set_'): key = name[4:] return lambda v: self._settings.update({key: v}) raise AttributeError(name) c = Config() print(dir(c)) # Shows get_* and set_* methods for each setting
此 Config
__dir__ 列出这些动态方法,以使其可以通过 dir()
和 IDE 自动完成功能发现。
__getattr__
方法处理实际的属性访问,而 __dir__
确保这些动态属性出现在列表中。
过滤属性
__dir__
还可以过滤属性,以从属性列表中隐藏实现细节或敏感数据。
class SecureData: def __init__(self, public, secret): self.public_data = public self._secret_data = secret def __dir__(self): return [attr for attr in super().__dir__() if not attr.startswith('_') or attr == '__dir__'] sd = SecureData("Open info", "Top secret") print(dir(sd)) # Doesn't show _secret_data
此实现过滤掉大多数以下划线开头的名称(在 Python 中被认为是私有的),除了像 __dir__
本身这样的特殊方法。
此模式对于创建更清晰的公共接口,同时将内部实现细节隐藏在随意检查之外非常有用。
继承行为
此示例演示了 __dir__
如何与继承一起工作,以及如何在子类中正确扩展它。
class Base: def __dir__(self): return ['base_attr', 'common_method'] class Derived(Base): def __init__(self): self.derived_attr = "value" def __dir__(self): base_attrs = super().__dir__() derived_attrs = ['derived_attr', 'new_method'] return sorted(set(base_attrs + derived_attrs)) def new_method(self): pass d = Derived() print(dir(d)) # Shows attributes from both classes
Derived
类将其自身的属性与来自 Base
类的属性结合。 使用 super().__dir__()
确保正确的继承行为。
在创建类层次结构时,此模式很重要,其中每个类都将其自身的属性添加到父类提供的属性中。
最佳实践
- 保持一致性: 确保 __dir__ 与实际可访问的属性匹配
- 包含特殊方法: 考虑包含重要的双下划线方法
- 保留默认值: 适当时与 super().__dir__() 结合使用
- 保持最新: 在 __dir__ 中反映动态属性更改
- 文档行为: 记录任何特殊过滤或添加
资料来源
作者
列出所有 Python 教程。