Python_面向对象:继承

一、继承概念

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

二、继承特点

继承的特点:

  1. 子类对象可以直接访问父类中未私有化的属性和方法
  2. 子类对象不可以直接调用父类中私有属性和私有方法
  3. 父类对象不能访问子类特有的属性和方法
  4. 继承具有传递性

继承的优缺点:

  1. 优点:可以简化代码,减少冗余;可提高代码的可维护性;提高代码的安全性;是多态的前提
  2. 缺点:在继承关系中,耦合性是比较高的【如果修改父类,子类也随之发生改变】

解释:耦合性和内聚性被用来描述类与类之间的关系,耦合性越低,内聚性越高,说明代码越好

复制代码
# 定义父类
class Person:

    def __init__(self, name):
        self.name = name
        self.__age = 18

    def eat(self):
        print(F"{self.name}要吃饭")

    def __drink(self):
        print(F"{self.name}要喝水")


# 定义子类
class Police(Person):

    def maintain_peace(self):
        print(F"{self.name}能维护治安")


# 定义子类
class SpecialPolice(Police):

    def counter_terrorism(self):
        print(F"{self.name}能反恐")


# 创建父类对象
xiaohong = Person("小红")
# 创建子类对象
xiaojiang = Police("小江")
xiaoming = SpecialPolice("小明")

# 1.子类对象可以直接访问父类中未私有化的属性和方法
print(xiaojiang.name)
xiaojiang.eat()

# 2.子类对象不可以直接调用父类中私有化的属性和方法
# xiaojiang.__drink() # AttributeError: 'Police' object has no attribute '__drink'

# 3.父类对象无法访问子类中特有的属性和方法
# xiaohong.maintain_peace()   # 报错 AttributeError: 'Person' object has no attribute 'maintain_peace'

# 4.继承具有传递性
xiaoming.eat()  # 能访问Police类继承的方法
复制代码

三、单继承&多继承

继承分为单继承和多继承。

单继承:一个子类只有一个父类,子类具有父类所有属性和方法。

多继承:一个子类有多个父类,子类具有多个父类的属性和方法。

3.1 单继承

3.1.1 语法 

父类:

  class 父类类名(object):

  类体【子类公共部分】

子类:

  class 子类类名(父类类名):

  类体【子类特有的部分】

注意:object是所有类的父类

3.1.2 代码演示

复制代码
# 定义父类
class Person:

    def __init__(self, name):
        self.name = name

    def eat(self):
        print(F"{self.name}要吃饭")

    def drink(self):
        print(F"{self.name}要喝水")


# 定义子类
class Police(Person):

    def maintain_peace(self):
        print(F"{self.name}是警察,能维护治安")


# 创建父类对象
xiaohong = Person("小红")
xiaohong.eat()
xiaohong.drink()

# 创建子类对象
xiaoming = Police("小明")
xiaoming.eat()
xiaoming.drink()
xiaoming.maintain_peace()
复制代码

3.2 多继承

3.2.1 语法

父类:

  class 父类类名1(object):

  类体【子类公共部分】

父类:

  class 父类类名2(object):

  类体【子类公共部分】

子类:

  class 子类类名(父类类名1, 父类类名2):

  类体【子类特有的部分】

3.2.2 代码演示

复制代码
# 定义父类1
class Person:

    def __init__(self, name):
        self.name = name

    def eat(self):
        print(F"{self.name}要吃饭")

    def drink(self):
        print(F"{self.name}要喝水")


# 定义父类2
class Police:

    def __init__(self, name):
        self.name = name

    def maintain_peace(self):
        print(F"{self.name}能维护和平")


# 定义子类
class SpecialPolice(Person, Police):

    def counter_terrorism(self):
        print(F"{self.name}能反恐")


# 创建子类对象
xiaojiang = SpecialPolice("小江")
xiaojiang.eat()
xiaojiang.drink()
xiaojiang.maintain_peace()
xiaojiang.counter_terrorism()
复制代码

3.2.3 mro多继承的调用顺序

多继承时,父类之间应尽量避免使用重名的方法或属性;反之如果继续的父类存在同名的属性或方法,应该尽量避免使用多继承。

因为当存在相同的属性或方法时,会在调用该属性或方法时产生混淆的情况,即不清楚到底调用的哪个父类的属性或方法。

如果在不清楚父类存在同名属性或方法的情况下调用了这些属性或方法,那怎么知道调用的是哪个父类的呢?

那就需要使用  类名.__mro__  查看python的方法解析顺序。(mro既是Method Resolution Order方法解析顺序)

复制代码
class TestA:
  
  def test(self):
        print("A类的test方法")


class TestB:

    def test(self):
        print("B类的test方法")


class TestC(TestB, TestA):

    def demo(self):
        pass


c = TestC()
c.test()  # B类的test方法
print(TestC.__mro__) 
# 输出:(class '__main__.TestC'>, <class '__main__.TestB'>, <class '__main__.TestA'>, <class 'object'>)
# 说明:元组中的顺序就是调用类的顺序,比如c对象调用test方法,python会先去TestC中查找test,若没查找到则继续在TestB中查找,
# 若在B中查找到了test方法,则直接执行该方法,不再在后续的类中查找test方法,利用该原理就可以达到方法重写的功能。
复制代码

四、重写父类方法

当继承的父类的方法完全不能满足开发需求时,就需要对父类的方法完全重写。

实现重写的方法为在子类中构造一个相同名称的方法,当调用这个方法时,就会优先调用子类中的方法。实现该功能的原理是MRO即方法解析顺序。

复制代码
class TestA:

    def test(self):
        print("A类的test方法")


class TestB(TestA):

    def test(self):
        print("B类重写的test方法")


b = TestB()
b.test()  # 输出:B类重写的test方法
print(TestB.__mro__)  # (<class '__main__.TestB'>, <class '__main__.TestA'>, <class 'object'>)
复制代码

五、修改父类方法

当继承的父类的方法不完全满足开发需求时,就需要在子类中重写部分需求,那么就需要在子类中调用父类中的方法,将父类现有的方法应用到子类中。

在子类中调用父类的方法有3种:

  1. 父类名.父类方法(self, *args, **kwargs)
  2. super().父类方法(*args, **kwargs)
  3. super(子类名, self).父类方法(*args, **kwargs)

上面3中方法在单继承中功能是一样的,在多继承中方法1能执行指定父类的方法,方法2和方法3是按 mro 的解析顺序执行。

复制代码
class Bus(object):

    def __init__(self):
        print("公交车类初始化方法")

    def run(self):
        print("公交车这样跑")


class Bike(object):
    def __init__(self):

        print("自行车类初始化方法")

    def run(self):
       print("自行车这样跑")


class Car(Bus, Bike):

    def __init__(self, type):
        # 父类属性不够,在子类中新增属性
        self.type = type

        # 继承父类方法的3种方式
        # 1、父类名.父类方法(self, *args, **kwargs)
        Bike.__init__(self)

        # 2、super().父类方法(*args, **kwargs)
        super().__init__()

        # 3、super(子类名, self).父类方法(*args, **kwargs)
        super(Car, self).__init__()

    def run(self):
       # 修改父类方法
        Bus.run(self)
        super().run()
        super(Car, self).run()


c = Car("a")
c.run()
复制代码

执行结果

 

posted @   码上测  阅读(210)  评论(0编辑  收藏  举报
编辑推荐:
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
阅读排行:
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· 软件产品开发中常见的10个问题及处理方法
· Vite CVE-2025-30208 安全漏洞
· MQ 如何保证数据一致性?
点击右上角即可分享
微信分享提示