面向对象(Python):学习笔记之继承
发布日期:2021-06-30 15:42:45 浏览次数:2 分类:技术文章

本文共 4865 字,大约阅读时间需要 16 分钟。

文章目录

继承
面向对象的三大特性:

  1. 封装:根据职责将属性和方法封装到一个抽象的类中

  2. 继承:继承实现代码的复用/重用,相同的代码不需要重复的编写

  3. 多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

1 单继承

1.1 单继承的概念 语法和特点

①. 单继承的概念

子类拥有父类的所有的方法和属性

②. 单继承的语法

class 子类名(父类名):	pass
  • 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
  • 子类中应该根据职责,封装子类中特有的属性和方法

首先让看一下 使用继承不使用继承 的区别.

在这里插入图片描述
如果不使用继承,开发一个动物类与狗类,则代码如下:

class Animals:    def eat(self):        print("吃")    def drink(self):        print("喝")    def run(self):        print("跑")    def sleep(self):        print("睡")        class Dog:    def eat(self):        print("吃")    def drink(self):        print("喝")    def run(self):        print("跑")    def sleep(self):        print("睡")    def bark(self):        print("汪汪汪")# 创建一个动物对象--狗对象wangcai_1 = Animals()wangcai_1.eat()wangcai_1.drink()wangcai_1.run()wangcai_1.sleep()wangcai_2 = Dog()wangcai_2.eat()wangcai_2.drink()wangcai_2.run()wangcai_2.sleep()wangcai_2.bark()

运行结果:

在这里插入图片描述
在这里可以看到,Animales类和Dog类有着四个函数是相同的,如果不使用继承,代码会非常冗余.如果再开发一个哮天犬类呢,毫无疑问代码会非常长且多余.
并且如果动物喝水的方法需要修改,我们则需要修改每一个类中的喝水方法,这显然太过于繁琐.

如果使用继承:

class Animals:    def eat(self):        print("吃")    def drink(self):        print("喝")    def run(self):        print("跑")    def sleep(self):        print("睡")class Dog(Animals):    def bark(self):        print("汪汪汪")  wangcai = Dog()wangcai.eat()wangcai.drink()wangcai.run()wangcai.sleep()wangcai.bark()

运行结果:

在这里插入图片描述
很显然,Dog子类继承了Animales的所有属性和方法.
而使用继承后,代码显然间带了许多.

③. 几个专业术语

  • Dog类是Animal类的子类,Animal是Dog的父类,Dog类是Animal类继承
  • Dog类是Animal类的派生类,Animal类是Dog的基类,Dog类是Animal类派生

④. 单继承的传递性

  • C类从B类继承,B类又从A类继承
  • 则C类具有B类和A类的所有属性和方法

即:子类拥有父类以及父类的父类中封装的所有属性和方法

class Animals:    def eat(self):        print("吃")    def drink(self):        print("喝")    def run(self):        print("跑")    def sleep(self):        print("睡")class Dog(Animals):    def bark(self):        print("汪汪汪")class XiaoTianQuan(Dog):    def fly(self):        print("我飞了")xtq = XiaoTianQuan()xtq.eat()xtq.drink()xtq.run()xtq.sleep()xtq.bark()xtq.fly()

运行结果:

在这里插入图片描述
注意:子类只能继承自己的父类中的属性和方法,而不能继承和自己的父类从一个爷爷类中派生出来的类的方法.
即:XiaoTianQuan类不能继承Cat类中的方法

1.2 方法的重写

  • 子类拥有父类的所有属性和方法
  • 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发.

方法的重写的应用场景:

  • 当父类的方法实现不能满足子类的需求时,可以对方法进行重写(Override)
    在这里插入图片描述
    如果在子类中,对父类的方法进行了重写,则会执行子类中的方法而不执行父类中的方法.
    如图:
    在这里插入图片描述

重写父类方法的两种情况:

  1. 覆盖父类的方法
    ①如果在开发中,父类的方法实现和子类的方法实现,完全不同
    ②就可以使用覆盖的方式,在子类中重新编写父类的方法实现
    具体的实现方式:就相当于在子类中定义了一个和父类同名的方法并实现
    重写之后,在运行的时候,只会调用子类中重写的方法,而不会调用父类中封装的方法
  2. 对父类方法进行扩展
    ①如果在开发中,子类的方法实现中包含父类的方法实现,即父类中原本封装的方法实现是子类方法的一部分.
    ②就可以使用扩展的方式
    Ⅰ.在子类中重写父类的方法
    Ⅱ.在需要的位置使用super().父类方法来调用父类方法的执行
    Ⅲ.代码其他的位置针对子类的需求,编写子类特有的代码实现

关于super
  • 在python中,super是一个特殊的类
  • super()就是使用super类创建出来的对象
  • 最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现

除此之外,调用父类名还有另外一种方式(Not important)

在Python 2.x的时候,如果需要调用父类的方法,可以使用以下方式

  • 父类名.方法(self)
  • 不推荐使用,因为一旦父类发生变化,方法调用位置的类名同样需要进行修改.

提示:

  • 在开发时,父类名 和 super()两种方式不要混用
  • 如果使用当前子类名调用方法,会形成递归调用,出现死循环

class Animals:    passclass Dog(Animals):    def bark(self):        print("汪汪汪")class XiaoTianQuan(Dog):    def fly(self):        print("我飞了")    def bark(self):        # 1.针对子类特有的需求,编写代码        print("我不想汪汪汪")        # 2.保留父类的方法        super().bark()        # 使用 父类名.方法(self)        # Dog.bark(self)        # 3.增加其他子类代码        print("123123")xtq = XiaoTianQuan()xtq.bark()

运行结果:

在这里插入图片描述
即:
如果向保留父类中的方法,首先要重写该方法,然后使用super().父类方法对其进行保留(调用),然后可以看情况增加后续代码.即实现了我们在原有父类方法上进行扩充的目的.

1.3 父类的私有属性和私有方法

  • 子类对象不能再自己的方法内部,直接访问父类的私有方法或者私有属性

  • 子类对象可以通过父类的公有方法间接访问到私有属性或私有方法

    ①私有属性、方法 是 对象的隐私,不对外公开,外界以及子类都不能直接访问
    ②私有属性、方法 通常用于做一些内部的事情
    示例:
    在这里插入图片描述

  • B 的对象不能直接访问_num2属性

  • B 的对象不能在demo方法内访问_num2属性

  • B 的对象可以在demo方法内,调用父类的test方法

  • 父类的test方法内部,能够访问_num2属性和_test方法

class A:    def __init__(self):        self.num1 = 100        self._num2 = 200    def _test(self):        print("私有方法 %d %d" % (self.num1, self._num2))    def test(self):        print("父类的公有方法")        self._test()        print("私有属性 %d" % self._num2)class B(A):    def demo(self):        print("%d" % self.num1)        self.test()b = B();print(b)b.demo()

运行结果:

在这里插入图片描述

2 多继承

2.1 多继承的概念 语法和特点

① 多继承的概念

  • 子类可以拥有多个父类,并且具有所有父类的属性和方法
  • 例如:孩子会继承自己父亲和母亲的特征
    在这里插入图片描述

②多继承的语法

class 子类名(父类名1,父类名2....):	pass
class A:    def test(self):        print("test 方法")class B:    def demo(self):        print("demo 方法")class C(A, B):    """多继承可以让子类对象    同时具有多个父类的属性和方法"""    pass# 创建子类对象c = C()c.test()c.demo()

运行结果:

在这里插入图片描述

2.2 多继承的注意事项

Question:

如果不同的父类中存在同名的方法,子类对象在调用时候,会调用哪一个父类中的方法呢?
提示:开发时,应该尽量避免这种容易产生混淆的情况!如果父类之间存在同名的属性或者方法,应该尽量避免使用多继承.
在这里插入图片描述
这种情况下,在底层代码设计中,会针对不同情况进行不同选择.
比如针对继承循序:
在这里插入图片描述
当然,不止有这一种选择方式.

2.3 Python中的MRO-----方法搜索顺序

(仅供科普,不推荐使用重名多继承调用)

  • python中针对类提供了一个内置属性__mro__可以查看方法搜索顺序
  • MRO是 method resolution order,主要用于在多继承时判断方法,属性的调用
    在这里插入图片描述
  • 在搜索方法时,是按照__mro__的输出结果从左至右的顺序查找到
  • 如果在当前类中找到方法,就继续执行,不在搜索
  • 如果没有找到,就查找下一个类中是否有对应的方法,如果找到,就直接执行,不在搜索
  • 如果找到最后一个类,还没有找到方法,程序报错

2.4 新式类与旧氏(经典)类

object是python中为所有对象提供的基类,提供一些内置的属性和方法,可以调用dir函数进行查看

  • 新式类:以object为基类的类,推荐使用
  • 经典类:不以object为基类的类,不推荐使用
  • 在Python 3.x中,定义类时,如果没有指定父类,会默认使用object作为该类的基类–Python 3.x中定义的类都是新式类
  • 在Python 2.x中,定义类时,如果没有指定父类,则不会使用object作为基类

新式类和经典类在使用多继承的时候,会影响到方法的搜索顺序

为了保证编写的代码能够同时在Python 2.x和Python 3.x中运行

在定义类的时候,如果没有父类,建议统一继承自 object

class 类名(object):	pass

转载地址:https://kaisarh.blog.csdn.net/article/details/103095736 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:C#:系统学习笔记(一)MVC基础篇
下一篇:C#:常用字符整理自用

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年05月04日 08时39分52秒