为何namedtuple实例属性会被类属性遮蔽?
为什么继承namedtuple的类中,类属性会遮蔽实例属性?
这个现象确实有点反直觉,咱们一步步拆解背后的原因:
1. 普通类的属性查找逻辑
先回到你给出的普通类例子:
class C(object): a="class_a" def __init__(self, a): self.a = a c = C(a="obja") print(c.a) # 输出 obja
当你访问c.a时,Python的属性查找顺序是:
- 先检查实例
c的__dict__(普通类实例默认有这个字典存储实例属性),发现里面有a,直接返回它的值obja - 如果实例
__dict__里没有,才会去类C的属性里找class_a
这就是为什么普通类里实例属性会遮蔽类属性。
2. namedtuple的特殊本质
再看继承namedtuple的情况:
import collections class C(collections.namedtuple("CBase", ['a', ])): a="class_a" c = C(a="obja") print(c.a) # 输出 class_a
这里的核心是:namedtuple生成的是元组的子类,它的实例是不可变元组,没有自己的__dict__存储实例属性。
namedtuple所谓的“实例属性”,其实是通过父类(这里的CBase)的属性访问逻辑映射到元组元素的——比如c.a本质等价于c[0],但这种映射是在父类层面实现的。
3. 子类的属性查找优先级
当你访问c.a时,因为实例c没有__dict__,Python会直接去当前类C的属性里查找,发现存在类属性a="class_a",就直接返回这个值了,根本不会继续去父类CBase里找那个映射到元组元素的“a”。
如果把子类的类属性去掉:
import collections class C(collections.namedtuple("CBase", ['a', ])): pass c = C(a="obja") print(c.a) # 输出 obja
这时候Python找不到当前类的a,才会去父类CBase里找对应的映射,返回元组元素的值。
总结
简单来说:
- 普通类的实例属性存在于实例的
__dict__,查找优先级高于类属性 - namedtuple实例没有
__dict__,它的“实例属性”是父类提供的映射 - 子类定义的类属性在查找顺序中优先级高于父类的映射属性,所以会遮蔽掉namedtuple的实例值
内容的提问来源于stack exchange,提问作者user48956
相关产品推荐
相关产品推荐

