You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:05:00