Python多继承中子类访问父类属性的机制解析

清欢
清欢
发布时间:2026-10-14| 5人浏览过
原创

本文深入解析Python多继承中子类访问父类属性的现象。通过代码示例揭示,看似子类调用父类方法访问父类属性,实则是子类实例在操作。核心在于self始终指向子类实例,父类属性和方法被“转移”至子类实例中,并非存在隐藏的继承关系。

Python继承基础与属性访问现象

在面向对象编程体系中,继承是一项核心机制,允许子类复用父类的方法与属性。

参考以下代码示例:


class Father:
    def __init__(self):
        self.address = '上海'

    def say(self):
        print('我是爸爸')

class Son(Father):
    def __init__(self):
        super().__init__()

    def say(self):
        print('我是儿子')

son = Son()
print(son.address)

其运行结果如图所示:

观察可知,子类本身并未定义 self.address 属性,但在直接打印时并未报错,而是自动调用了父类的 address 属性。

反之,若子类和父类均缺失该属性,程序将抛出错误,具体表现如下:

多继承中的属性查找困惑

Python 支持 Python 多继承,即一个子类可拥有多个父类。请查看以下代码:


class GrandFather:
    def __init__(self):
        self.address = '上海'

    def say(self):
        print('我是爸爸')

class Father:
    def __init__(self):
        self.age = 100
    
    def where(self):
        print('我现在住在:', self.address)

class Son(GrandFather, Father):
    def __init__(self):
        super().__init__()

    def say(self):
        print('我是儿子')

son = Son()
son.where()

运行效果如图所示:

仔细观察代码逻辑,会发现一处看似异常的现象。调用 son.where() 方法时,由于 Son 类未定义该方法,解释器沿继承链查找至 Father 父类,并执行其中的 where() 方法,此过程符合预期。

然而后续步骤显得不合常理。在 where() 方法内部,代码尝试访问 self.address 属性。问题在于,Father 类并未定义该属性,且 Father 作为根类也没有父类。那么,address 属性究竟源自何处?

这是否意味着在开发者视野之外,GrandFather 类悄悄成为了 Father 的父类?若如此,GrandFather 既是 C 的父类,又是 C 的父类的父类,即 GrandFather 既是父亲又是祖父?

实际上,这种混乱的继承关系并不存在。要解释这一现象,需从 self 的本质入手。

解析self的本质与实例归属

我们知道,类的属性通常以 self 开头,方法的第一个参数也是 self 。那么 self 究竟代表什么?通过以下简短代码进行验证:


class A:
    def get_self(self):
        return self

test = A()
what_is_self = test.get_self()

test is what_is_self

运行结果如图所示:

从图中可见,self 实际上即为该类的实例对象。进一步考察存在继承关系的情况:


class A:
    def get_self(self):
        return self

class B(A):
    def __init__(self):
        ...

test = B()
what_is_self = test.get_self()

print(what_is_self)

结果显示,尽管在 A 类的 .get_self() 方法中返回了 self ,但该 self 实际上是 B 类的实例。这是因为我们仅初始化了 B 类,从未初始化 A 类。尽管 A 是 B 的父类,但父类的 self 最终都归属于子类实例。

理解这一点后,前文的问题便迎刃而解。我们增加更多打印信息以观察细节:

请注意图中红线标注部分,self 始终指向 Son 类的实例。因此,在初始化 .address 时,实质是初始化 Son 实例的 .address 属性。后续在 .where 中调用 address 时,读取的也是 Son 实例的 address 属性。因此,并不存在 Father 类去读取 GrandFather 类属性的情况,自始至终均由 Son 类的实例执行操作。

多继承属性覆盖与映射机制总结

综上所述,在继承机制下,若子类与父类拥有同名属性或方法,子类定义优先。若子类未定义,则父类的属性和方法会直接“映射”到子类实例中。所有看似由父类执行的操作,实际上均由子类实例完成。上述代码逻辑可近似等价于以下简化理解:

由于 say 方法在子类中已定义,子类覆盖父类实现,以子类的 say 方法为准。而 where 和 address 因子类未定义,Father 类的 where 方法与 GrandFather 中的 address 属性,均直接作用于子类实例。

本文关于 Python 多继承中这一看似诡异现象的解析至此结束。如需了解更多相关内容,建议查阅本站过往文章或继续浏览后续教程,感谢大家的支持。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。