面向对象(三)继承和多态

继承

  什么是继承

    继承就是新建类的一种方式,新建的类我们称为子类或者派生类,被继承的类称为父类或基类。

    子类可以使用父类中的属性或方法。

  为什么要使用继承

    类解决了对象和对象之间的代码冗余问题。

    继承解决了类和类之间的代码冗余问题。

  如何使用继承

    在Python2中的子类存在区别:

      新式类:继承了object类的子子孙孙类都是新式类。

      经典类:没有继承了object类的子子孙孙类都是经典类。

 

 

类的继承

复制代码
# 定义一个公共的类
class People:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


# 定义一个People类的子类
class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        # 可使用父类中的属性或方法
        People.__init__(self, name, age, gender)
        self.course = course

    def choice_course(self, course):
        self.course.append(course)
        print('%s选课%s成功' % (self.name, self.course))


stu = Student('tom', 18, 'male', 'python')
print(stu.name)
# 结果为tom
复制代码

属性的查找顺序

  单继承下的属性查找顺序

    单继承的情况下属性的查找是由子类一路向上查找。

    在查找时要注意参数self指的一直是调用方法的属性。

复制代码
class Foo:
    def f1(self):
        print('Foo.f1')

    # 4.在Foo类中找到f2方法并执行
    def f2(self):
        # 5.输出Foo.f2
        print('Foo.f2')
        # 6.此时的self指的是obj也就是Bar类
        self.f1()


# 3.在Bar类中找f2方法但没找到
class Bar(Foo):
    # 7.执行Bar类的f1方法
    def f1(self):
        # 8.输出Bar.f1
        print('Bar.f1')


# 1.调用Bar类
obj = Bar()
# 2.调用f2方法
obj.f2()
# 结果:
# Foo.f2
# Bar.f1
复制代码

 

  多继承下的属性查找顺序

    经典类:按照深度优先的查找顺序。

    在多继承时,经典类会一次性查到底,然后才去第二个父类找。

    新式类:按照广度优先的查找顺序。

    在多继承时,新式类在查到继承object类的父类时会先不查,直到没有其他父类才会去查询。

 

 

 

 

复制代码
class A(object):
    def test(self):
        print('from A')


class B(A):
    # def test(self):
    #     print('from B')
    pass


class C(A):
    # def test(self):
    #     print('from C')
    pass


class D(B):
    # def test(self):
    #     print('from D')
    pass


class E(C):
    # def test(self):
    #     print('from E')
    pass


class F(D, E):
    # def test(self):
    #     print('from F')
    pass


f1 = F()
f1.test()
# 经典类顺序F->D->B->A->E->C
# 新型类顺序F->D->B->E->C->A
查询顺序
复制代码

 

super()和mro列表

  super()方法提供了除了指名道姓外另一种从父类中调用属性的方式。

复制代码
# 定义一个公共的类
class People:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


# 定义一个People类的子类
class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        # 可使用父类中的属性或方法
        # People.__init__(self, name, age, gender)
        # super()方法在Python2中相当于super(People,self)
        # 可直接将自己传入,不用再写self
        super().__init__(name, age, gender)
        self.course = course

    def choice_course(self, course):
        self.course.append(course)
        print('%s选课%s成功' % (self.name, self.course))


stu = Student('tom', 18, 'male', 'python')
print(stu.name)
# 结果为tom
复制代码

  super()方法的查询顺序是按照mor列表从左到右的顺序进行查找。

  因此即使没有明显的继承关系,使用super()方法依然可以找到。

复制代码
class A:
    # 4.A中有text开始调用
    def test(self):
        print('from A.test')
        # 5.super方法调用text,即使A并没有父类,也会按照mor列表顺序去B中找
        super().test()


class B:
    # 6.B中有text则调用
    def test(self):
        print('from B')


# 3.c中没有先去父类A中找
class C(A, B):
    pass


# 1.实例化c
c = C()
# 2.查找text
c.test()
# 结果为
# from A.test
# from B
print(C.mro())
# 结果为[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
# 因此super的查找顺序为C->A->B
复制代码

 

 

多态和多态性

  多态

    多态指的是事物的不同形态。

    在现实生活中:水的形态分为液态水、冰、水蒸气。

    在电脑中:文件有多种形态:文本文件,可执行文件等。

  多态性

    多态性是指在不考虑实例类型的情况下使用实例。

    好处是能增加文件的灵活性和可扩展性。

复制代码
import abc


# 抽象类: 抽象类只能被继承,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    # 该方法已经是抽象方法了如果子类没有对应方法会直接报错
    @abc.abstractmethod
    def speak(self): pass


class People(Animal):
    def speak(self):
        print('嗷嗷嗷')


class Pig(Animal):
    def speak(self):
        print('哼哼哼')


class Dog(Animal):
    def speak(self):
        print('汪汪汪')


obj = People()
obj1 = Pig()
obj2 = Dog()


# 多态带来的特性:在不用考虑对象数据类型的情况下,直接调用对应的函数
def animal(animal):
    return animal.speak()


animal(obj)
animal(obj1)
animal(obj2)
# 结果:
# 嗷嗷嗷
# 哼哼哼
# 汪汪汪
复制代码

 

posted @   临江沂水  阅读(47)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示