getattr(obj, 'attr_name', default_value)在属性不存在时返回默认值而非报错;它只判断属性是否存在,不检查值是否为falsy;不支持点号嵌套访问,需手动链式调用或用attrgetter。

getattr 拿不到属性时怎么不报错
直接给第三个参数,它就是默认值。没这个参数,getattr 遇到不存在的属性就抛 AttributeError,不是返回 None —— 这点很多人误以为是默认行为。
- 写法必须是
getattr(obj, 'attr_name', default_value),第三个位置只能是值,不能是函数或表达式(除非你显式调用) - 如果属性存在但值为
None、0、False,getattr仍会原样返回,不会触发默认值——它只管“有没有”,不管“是不是 falsy” - 默认值可以是任意类型:字符串、数字、空列表、甚至 lambda(但注意别写成
lambda: ...不调用,得写(lambda: ... )()才生效)
想动态获取嵌套属性,getattr 能链式调用吗
不能。getattr 一次只查一层。比如 obj.user.profile.name,你得自己拆解或用工具函数封装。
- 常见错误:写
getattr(obj, 'user.profile.name')—— 这是在找一个叫user.profile.name的**单层属性名**,不是路径遍历 - 简单替代:用
functools.reduce+getattr,例如reduce(lambda o, k: getattr(o, k, None), ['user', 'profile', 'name'], obj) - 更稳的做法是用第三方库如
operator.attrgetter('user.profile.name'),它原生支持点号路径,且可设默认值(通过__call__或包装)
getattr 默认值写 None 安全吗
语法上安全,但语义上容易埋坑。尤其当你后续对返回值做方法调用或下标访问时,None 会立刻崩。
- 比如
getattr(obj, 'items', None).append(1),一旦items不存在,就报AttributeError: 'NoneType' object has no attribute 'append' - 推荐按使用场景选默认值:要列表就给
[],要字典就给{},要字符串就给'',避免后续判空逻辑爆炸 - 如果真不确定类型又不想提前假设,至少包一层检查:
val = getattr(obj, 'x', None); if val is not None: ...
getattr 在 hasattr 之后还用吗
没必要。先 hasattr(obj, 'attr') 再 getattr(obj, 'attr') 是典型重复查找,CPython 里会多一次字典键搜索。
立即学习“Python免费学习笔记(深入)”;
-
hasattr底层就是靠捕获getattr的异常实现的,两次调用等于做两遍属性查找 - 正确姿势:直接
getattr(obj, 'attr', SENTINEL),然后判断是否等于SENTINEL(别用None,防止属性本身是None) - 如果 SENTINEL 需要唯一性,用
object()实例,比如_sentinel = object(),再比is _sentinel










