
getattr() 的核心逻辑是:仅当显式传入 default 参数时才返回默认值,否则必须抛出 AttributeError;其 Python 模拟实现需用哨兵对象(如 object())区分“未提供 default”和“传入了 None”两种情况。
`getattr()` 的核心逻辑是:仅当显式传入 `default` 参数时才返回默认值,否则必须抛出 `attributeerror`;其 python 模拟实现需用哨兵对象(如 `object()`)区分“未提供 default”和“传入了 `none`”两种情况。
getattr(obj, name, default) 是 Python 内置函数,用于安全访问对象属性。它的标准行为可概括为三点:
- 若
obj存在名为name的属性(包括实例属性、类属性、继承属性),直接返回该属性值; - 若属性不存在,且调用了三参数形式(即提供了
default),则返回default值; - 若属性不存在,且仅使用两参数形式(即未提供
default),则无条件抛出AttributeError。
关键在于:能否准确判断用户是否“显式传入了 default”。常见错误实现(如用 default is None 判断)会失败,因为 None 是合法的、有意义的默认值——正如示例中 getattr(test, "unknown_value", None) 本应静默返回 None,但错误实现却误判为“未提供 default”,进而抛出异常。
✅ 正确的 Python 层模拟实现如下:
_NOTSET = object() # 哨兵对象,全局唯一,不可能被用户传入
def getattr(obj, name, default=_NOTSET):
try:
return object.__getattribute__(obj, name)
except AttributeError:
if default is not _NOTSET: # 严格身份比较
return default
raise⚠️ 注意事项:
立即学习“Python免费学习笔记(深入)”;
- 必须使用
is not _NOTSET而非!= _NOTSET或default is None,确保语义精确; -
object()创建的实例不可被序列化或哈希,但作为哨兵完全安全; - 实际 CPython 源码(bltinmodule.c#L1201)通过 C 层参数计数直接判断调用形式,无需哨兵,这是纯 Python 函数无法复现的底层能力。
总结:getattr 的设计哲学是“显式优于隐式”。它不把 None 视为“未设置”的标志,而是将其视为一个可接受的、有业务意义的默认值。因此,任何试图在 Python 中重实现它的代码,都必须借助不可伪造的哨兵对象来忠实还原这一契约。


















