Python 类的继承基础讲解

舞夢輝影
发布: 2025-09-21 22:53:01
原创
1010人浏览过
继承实现代码复用与“is-a”关系,如Dog和Cat继承Animal共享属性方法;多重继承需谨慎使用,易引发MRO复杂性;优先选择组合表达“has-a”关系以提升灵活性。

python 类的继承基础讲解

Python的类继承,简单来说,就是让一个新类(我们叫它子类或派生类)能够“学到”另一个已有的类(父类或基类)的各种能力和特性。这就像是生物学上的遗传,子代继承了父代的基因,但也可以在此基础上发展出自己的独特之处。核心目的就是代码复用,避免写重复的代码,同时也能更好地组织和管理代码结构,让它们之间存在一种“是”的关系,比如“狗是一种动物”。

在Python里,实现继承其实非常直接。当你定义一个类时,可以在类名后面括号里指定它要继承的父类。

class Animal:
    def __init__(self, name):
        self.name = name
        print(f"{self.name} 出生了。")

    def speak(self):
        raise NotImplementedError("子类必须实现这个方法")

    def move(self):
        print(f"{self.name} 正在移动。")

class Dog(Animal): # Dog 继承自 Animal
    def __init__(self, name, breed):
        super().__init__(name) # 调用父类的构造方法
        self.breed = breed
        print(f"这是一只 {self.breed} 的狗。")

    def speak(self): # 重写父类的 speak 方法
        return "汪汪!"

class Cat(Animal): # Cat 也继承自 Animal
    def __init__(self, name):
        super().__init__(name)
        print(f"这是一只猫。")

    def speak(self):
        return "喵喵!"

# 实例化
my_dog = Dog("旺财", "金毛")
print(f"{my_dog.name} 说:{my_dog.speak()}")
my_dog.move()

my_cat = Cat("咪咪")
print(f"{my_cat.name} 说:{my_cat.speak()}")
my_cat.move()
登录后复制

从上面这个例子能看出来,

Dog
登录后复制
Cat
登录后复制
都继承了
Animal
登录后复制
类的
name
登录后复制
属性和
move
登录后复制
方法。同时,它们也都有各自独特的属性(
Dog
登录后复制
breed
登录后复制
)和行为(各自实现了
speak
登录后复制
方法)。这里
super().__init__(name)
登录后复制
是个关键,它负责调用父类
Animal
登录后复制
的构造方法,确保
Animal
登录后复制
类的初始化逻辑也被执行。如果没有这行,
Dog
登录后复制
Cat
登录后复制
就不会拥有
name
登录后复制
属性,或者说,
Animal
登录后复制
类中定义的初始化逻辑就不会被触发。我个人在刚接触这块儿的时候,就经常忘记调用
super()
登录后复制
,然后发现一些属性没初始化,搞得一头雾水。

Python继承机制到底能解决哪些实际问题?

继承最直观的用处,就是代码复用。想想看,如果

Animal
登录后复制
有十几个通用的方法,比如
eat()
登录后复制
sleep()
登录后复制
breathe()
登录后复制
,如果不用继承,每个子类(
Dog
登录后复制
Cat
登录后复制
Bird
登录后复制
)都得重新写一遍这些方法,那代码量得多大,维护起来得多麻烦?有了继承,这些通用行为只需要在父类定义一次,子类就能直接用。这大大减少了冗余,也让代码更简洁。

立即学习Python免费学习笔记(深入)”;

再一个就是建立清晰的逻辑关系。继承表达的是一种“is-a”关系。比如“狗是一种动物”,“轿车是一种交通工具”。这种关系在建模现实世界时非常有用,它让你的程序结构更符合人类的认知,也更容易理解。当你想扩展功能时,比如要添加一个新的动物类型,你只需要创建一个新的子类继承

Animal
登录后复制
,然后实现它特有的部分就行,不需要从头开始写所有通用的东西。这让系统的可扩展性变得非常好。

此外,继承也为多态性打下了基础。虽然这听起来有点高级,但简单来说,就是不同的子类可以对同一个父类方法有不同的实现。比如上面的

speak()
登录后复制
方法,
Dog
登录后复制
Cat
登录后复制
都有,但它们说出来的话不一样。这样,你就可以写一个函数,它接受一个
Animal
登录后复制
对象作为参数,然后调用
animal.speak()
登录后复制
,具体发出什么声音,取决于传入的是
Dog
登录后复制
还是
Cat
登录后复制
对象。这让代码变得非常灵活,能够处理不同类型的对象,而无需关心它们的具体类型。

在Python中,多重继承是不是一个好主意?

Python是支持多重继承的,这意味着一个子类可以同时继承多个父类。这听起来功能很强大,但实际用起来,我个人觉得它是一把双刃剑,得小心翼翼地用。

硅基智能
硅基智能

基于Web3.0的元宇宙,去中心化的互联网,高质量、沉浸式元宇宙直播平台,用数字化重新定义直播

硅基智能 62
查看详情 硅基智能

多重继承的主要问题在于复杂性方法解析顺序(MRO)。当一个子类继承了多个父类,并且这些父类中存在同名的方法时,Python就需要一个规则来决定到底调用哪个父类的方法。这个规则就是MRO。Python采用C3线性化算法来确定MRO,虽然它很智能,但对于开发者来说,理解和预测MRO的行为有时候会非常烧脑,尤其是在继承链很深或者结构复杂的时候。这也就是所谓的“菱形继承问题”(Diamond Problem)的根源之一。

class A:
    def method(self):
        print("Method from A")

class B(A):
    def method(self):
        print("Method from B")

class C(A):
    def method(self):
        print("Method from C")

class D(B, C): # 多重继承
    pass

d = D()
d.method() # 到底会打印哪个?
print(D.__mro__) # 查看MRO
登录后复制

运行上面这段代码,你会发现它打印的是 "Method from B"。通过

D.__mro__
登录后复制
可以看到
D
登录后复制
的方法解析顺序是
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
登录后复制
。Python会按照这个顺序查找方法,找到第一个就停下。

所以,我的建议是:尽量避免滥用多重继承。在大多数情况下,你可以通过组合(Composition)或者使用Mixin(混入)类来达到类似的目的,而且代码会更清晰、更易于维护。Mixin是一种特殊的多重继承用法,它通常不带有自己的状态,只提供一些特定的功能方法,像“插件”一样被混入到其他类中。这种方式能有效减少多重继承带来的复杂性。

什么时候应该用继承,什么时候该用组合?

这是一个软件设计中非常经典且重要的问题。简单来说,它们表达了两种不同的关系:

继承(Inheritance):表达“is-a”关系。 当一个对象“是”另一个对象的一种特殊类型时,就应该考虑使用继承。

  • 例子:
    Dog
    登录后复制
    is a
    Animal
    登录后复制
    Car
    登录后复制
    is a
    Vehicle
    登录后复制
  • 优点: 代码复用,建立层次结构,支持多态。
  • 适用场景: 当你有一个明确的父子关系,子类是对父类的具体化或扩展,并且子类共享父类的核心行为和属性。

组合(Composition):表达“has-a”关系。 当一个对象“拥有”另一个对象作为其一部分时,就应该考虑使用组合。

  • 例子:
    Car
    登录后复制
    has an
    Engine
    登录后复制
    Computer
    登录后复制
    has a
    CPU
    登录后复制
  • 优点: 灵活性高,降低耦合度。一个对象可以通过组合不同的组件来获得不同的行为,而不需要复杂的继承链。
  • 适用场景: 当你希望一个类能够复用其他类的功能,但它们之间没有明确的“is-a”关系时。或者当你希望在运行时能够动态地改变一个对象的行为时。
# 组合的例子
class Engine:
    def start(self):
        return "Engine started!"

class Car:
    def __init__(self):
        self.engine = Engine() # Car 拥有一个 Engine 对象

    def drive(self):
        print(self.engine.start())
        print("Car is driving.")

my_car = Car()
my_car.drive()
登录后复制

在这个

Car
登录后复制
Engine
登录后复制
的例子中,
Car
登录后复制
并没有继承
Engine
登录后复制
,而是将
Engine
登录后复制
作为自己的一个成员变量。
Car
登录后复制
拥有一个
Engine
登录后复制
。这样设计的好处是,如果将来我想把
Engine
登录后复制
换成
ElectricMotor
登录后复制
,我只需要修改
Car
登录后复制
的构造函数或者提供一个方法来替换
Engine
登录后复制
实例,而不需要改变
Car
登录后复制
的继承结构。这比继承更灵活,也更符合“优先使用组合而非继承”的设计原则。

总的来说,如果你在纠结用继承还是组合,我的经验是:优先考虑组合。只有当你确定两个类之间存在强烈的“is-a”关系,并且继承能带来显著的复用和多态优势时,再选择继承。组合通常能带来更松散的耦合和更高的灵活性,这对于长期维护和扩展代码来说非常重要。

以上就是Python 类的继承基础讲解的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号