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 教程。