Python 继承、多继承、多重集成、多态

本贴最后更新于 387 天前,其中的信息可能已经沧海桑田

实践是检验真理的唯一标准:拷贝到pycharm一试便知。

类的特性:
1、继承:子类继承父类,就拥有了父类的所有方法和属性(私有方法和属性除外)
2、封装:隐藏内部的实现,对外公开接口或者方法
3、多态:一个事物有多种形态

一、继承

1、继承的写法

class Test02(Test01):

2、子类调用父类的方法

1、调用实例方法

self.方法名称()

2、初始化方法

1、子类没有写初始化方法:在调用父类方法的时候,会自动调用父类的初始化方法
2、子类有初始化方法,就会调用自己的初始化方法,不会自动调用父类的初始化方法,除非手动super().init()

3、super().init() 与 父类().init()区别

1、手动调用父类的初始化方法:super().init()
2、调用初始化方法的时候 super().init()不会存在重复调用父类初始化方法的问题
3、调用初始化方法的时候通过父类 ClassFu().init()会重复调用父类的初始化话方法
4、在调用普通方法的时候没有区别
5、super().init()调用初始化方法,实例属性才能被子类继承下来
6、ClassFu().init()调用初始化方法,实例属性未继承

4、子类调父类的普通方法(通过类实例调用(类实例、self))

1、父类与子类有同名的方法:通过子类的实例去调用,优先调用自己的方法
2、子类没有定义,父类定义了某个方法,调用的时候先查询子类是否有该方法,如果没有再查询父类
按继承顺序一次往上查询,查到就执行,查不到就报错。
3、方法的查询顺序(子类 -->父类-->爸爸的爸爸........一直查到object(基类))

5、子类(通过super())调父类的普通方法。

1、跳过子类,直接从父类去找对应的方法,按照继承顺序查找(从左往右),

方法的查询顺序(父类-->爸爸的爸爸........一直查到object(基类))

3、继承的使用场景

1、子类需要使用父类的方法和属性
2、重写父类方法:
在子类中,与父类同名方法内不添加 super().父类同名方
3、在父类方法上做拓展(类似装饰器):
在子类中,与父类同名方法内添加 super().父类同名方


# 父类
import time


class ClassFu:  # 相当于 ==> class Test01(object):
    name = "老王"

    def __init__(self):
        print("父类的初始化方法__init__")
        self.age = 20

    def test_01(self):
        time.sleep(2)
        print("父类ClassFu的方法test_01")

    def test_02(self):
        print("父类ClassFu的方法test_02")

    def test_04(self):
        print("父类ClassFu的方法test_04")


# 1、子类没有写初始化方法:在调用父类方法的时候,会自动调用父类的初始化方法
class ClassZi01(ClassFu):
    pass


# 2、子类有初始化方法,就会调用自己的初始化方法,不会自动调用父类的初始化方法
class ClassZi02(ClassFu):
    def __init__(self):
        print("子类ClassZi02的初始化方法__init__")


# 3、super().__init__() 与 父类().__init__()区别
class ClassZi03(ClassFu):
    def __init__(self):
        print("子类ClassZi03的初始化方法__init__")
        # 1、手动调用父类的初始化方法:super().__init__()
        # 不会存在重复调用父类初始化方法
        # 实例属性被子类继承
        super().__init__()


# 3、super().__init__() 与 父类().__init__()区别
class ClassZi04(ClassFu):
    def __init__(self):
        print("子类ClassZi04的初始化方法__init__")
        # 会重复调用父类的初始化话方法
        # 实例属性未继承
        ClassFu().__init__()


# 4、子类调父类的普通方法(通过类实例调用(类实例、self))
# 5、子类(通过super())调父类的普通方法。
class ClassZi05(ClassFu):
    def __init__(self):
        print("子类ClassZi05的初始化方法__init__")
        super().__init__()

    def test_01(self):
        print("子类ClassZi05的方法test_01")

    def test_03(self):
        print("子类ClassZi05的方法test_03")
        super().test_01()  # 用super() 子类有,也不用,从父类找
        self.test_04()  # 子类有,用子类,不用父类

    def test_04(self):
        print("子类ClassZi05的方法test_04")


# 3、继承的拓展 和 重写
# 子类 ClassZi06
class ClassZi06(ClassFu):

    def __init__(self):
        print("子类ClassZi06的初始化方法__init__")
        super().__init__()

    def test_01(self):
        print("子类ClassZi06的方法test_01")
        start_time = time.time()
        super().test_01()  # 不加这行是重写父类方法,加上是拓展父类方法
        end_time = time.time()
        return end_time - start_time


if __name__ == '__main__':
    # 2、子类调用父类的方法 ####################################################################################
    """2、初始化方法"""
    # 1、子类没有写初始化方法:会自动调用父类的初始化方法
    cl_z_1 = ClassZi01()
    # 父类的初始化方法__init__
    print('cl_z_1.age:', cl_z_1.age)  # 能调父类的实例属性
    # cl_z_2.age: 20

    # 2、子类有初始化方法:就只会调用自己的初始化方法,不掉父类...
    cl_z_2 = ClassZi02()
    # 子类ClassZi02的初始化方法__init__
    # print('cl_z_2.age:', cl_z_2.age)  # 不能调父类的实例属性,需super().__init__()
    # # AttributeError: 'ClassZi02' object has no attribute 'age'

    """3、super().__init__() 与 父类().__init__()区别"""
    print('cl_z_3 ==================================================================================')
    # 1、手动调用父类的初始化方法:super().__init__()
    # 2、调用初始化方法的时候super().__init__()不会存在重复调用父类初始化方法的问题
    cl_z_3 = ClassZi03()
    # 子类ClassZi03的初始化方法__init__
    # 父类的初始化方法__init__

    # 3、调用初始化方法的时候ClassFu().__init__()会重复调用父类的初始化话方法
    cl_z_4 = ClassZi04()
    # 子类ClassZi04的初始化方法__init__
    # 父类的初始化方法__init__
    # 父类的初始化方法__init__

    # 4、在调用普通方法的时候没有区别
    print('执行:cl_z_3.test_01()、cl_z_3.test_01():')
    cl_z_3.test_01()
    # 父类ClassFu的方法test_01
    cl_z_4.test_01()
    # 父类ClassFu的方法test_01

    # 5、super().__init__()调用初始化方法,实例属性才能被子类继承下来
    print('cl_z_3.__dict__:', cl_z_3.__dict__)
    # cl_z_3.__dict__: {'age': 20}
    print('cl_z_3.age:', cl_z_3.age)
    # cl_z_3.age: 20

    # 6、ClassFu().__init__()调用初始化方法,实例属性未继承
    print('cl_z_4.__dict__:', cl_z_4.__dict__)
    # cl_z_4.__dict__: {}
    # print('cl_z_4.age:', cl_z_4.age)  # 打印报错
    # # AttributeError: 'ClassZi04' object has no attribute 'age'

    # 父类的类属性 子类都能访问,无论是否有初始化方法、是否调用父类初始化方法
    print('ClassZi01.name:', ClassZi01.name)
    print('ClassZi02.name:', ClassZi02.name)
    print('ClassZi03.name:', ClassZi03.name)
    print('ClassZi04.name:', ClassZi04.name)
    # ClassZi01.name: 老王
    # ClassZi02.name: 老王
    # ClassZi03.name: 老王
    # ClassZi04.name: 老王

    """4、子类调父类的普通方法(通过类实例调用(类实例、self))"""
    print('cl_z_5 ==================================================================================')
    # 创建子类实例对象
    cl_z_5 = ClassZi05()
    # 子类ClassZi05的初始化方法__init__
    # 父类的初始化方法__init__

    # 1、父类与子类有同名的方法:通过子类的实例去调用,优先调用自己的方法
    cl_z_5.test_01()
    # 子类ClassZi05的方法test_01

    # 2、子类没有定义,父类定义了某个方法,调用的时候先查询子类是否有该方法,如果没有再查询父类
    cl_z_5.test_02()
    # 父类ClassFu的方法test_02

    """5、子类(通过super())调父类的普通方法。"""
    # 1、跳过子类直接从父类去找对应的方法,按照继承顺序查找(从左往右)
    cl_z_5.test_03()
    # 子类ClassZi05的方法test_03
    # 父类ClassFu的方法test_01
    # 子类ClassZi05的方法test_04

    # 3、继承的使用场景 ######################################################################################
    print('cl_z_6 ==================================================================================')
    cl_z_6 = ClassZi06()
    # 子类ClassZi06的初始化方法__init__
    # 父类的初始化方法__init__

    print(cl_z_6.test_01())
    # 子类ClassZi06的方法test_01
    # 父类ClassFu的方法test_01
    # 2.001312255859375

二、多继承

1、继承多个父类【掌握】

1、方法的查询顺序(子类 -->父类-->........object(基类))
2、其他的同单继承

# """1、继承多个父类【掌握】"""
class Test01:
    def test_01(self):
        print("Test01类的test_01")


class Test02:
    def test_02(self):
        print("Test02类的test_02")


class Test03:
    def test_03(self):
        print("Test03类的test_03")


class Test04(Test01, Test02, Test03):
    def test_04(self):
        print("Test04类的test_04")


if __name__ == '__main__':
    cl4 = Test04()
    cl4.test_01()
    # Test01类的test_01
    cl4.test_03()
    # Test03类的test_03

2、多重继承【了解】

1、多重继承会存在继承顺序错乱,导致python无法计算MRO表(继承关系图谱)
2、尽量不要用多重继承


# """2、多重继承【了解】"""
class Test01:
    def test_02(self):
        print("Test01类的test_01")


class Test02(Test01):
    def test_01(self):
        print("Test02类的test_02")


class Test03(Test01, Test02):
    def test_03(self):
        print("Test03类的test_03")


if __name__ == '__main__':
    cl3 = Test03()
    cl3.test_01()
    # TypeError: Cannot create a consistent method resolution
    # order (MRO) for bases Test01, Test02
  

三、多态【了解】

不好用,通常不这么用,通常直接一个类建立多个不同方法更方便。
例如场景:公司的方法已经用了很久,不好方便去改,就新建一个方法传入不同的类去调用他们相同的方法。

# """三、多态【了解】"""
class Dog:
    def eating(self):
        print("狗子在吃东西")


class Cat:
    def eating(self):
        print("小猫在吃东西")


def animal(obj):
    cl = obj()
    cl.eating()


if __name__ == '__main__':
    animal(Cat)
    animal(Dog)
    # 小猫在吃东西
    # 狗子在吃东西

5 操作
qq5942527 在 2023-04-06 12:09:32 更新了该帖
qq5942527 在 2023-04-06 12:08:51 更新了该帖
qq5942527 在 2023-04-06 12:04:14 更新了该帖
qq5942527 在 2023-04-06 11:28:44 更新了该帖 qq5942527 在 2023-04-06 11:21:18 更新了该帖
回帖
请输入回帖内容 ...