-----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出《Python编程思想》电子书,囊括了Python的核心技术,以及Python的主要函数库的使用方法。读者可以在「极客起源」 公众号中输入 160442 开始学习。-----------正文-----------继承是面向对象的3大特征之一(另两个特性是封装和组合),也是实现软件复用的重要手段。Python的继承是多继承机制,也就是一个子类可以同时有多个直接父类。1.  继承的语法Python子类继承父类的语法是在定义子类时,将多个父类放在子类之后的圆括号中。语法格式如下:

class SubClass(SuperClassl, SuperClass2,..)     # 类定义部分

从上面的语法格式来看,定义子类的语法非常简单,只需在原来的类定义后增加圆括号,并在圆括号中添加多个父类,即可表明该子类继承了这些父类。如果在定义一个 Python类时并未显式指定这个类的直接父类,则这个类默认继承 object类。因此,object类是所有类的父类,要么是其直接父类,要么是其间接父类。实现继承的类被称为子类,被继承的类被称为父类,也被称为基类、超类。父类和子类的关系是一般和特殊的关系。例如水果和香蕉的关系,香蕉继承了水果,香蕉是水果的子类,则香蕉是种特殊的水果。由于子类是一种特殊的父类,因此父类包含的范围总比子类包含的范围要大,所以可以认为父类是大类,而子类是小类。从实际意义上看,子类是对父类的扩展,子类是一种特殊的父类。从这个意义上看,使用继承来描述子类和父类的关系是不准确的,用扩展更恰当。因此,这样的说法更加准确:Banana类扩展了Fruit类。从子类的角度来看,子类扩展( extend)了父类,但从父类的角度来看,父类派生(derive)出子类。也就是说,扩展和派生所描述的是同一个动作,只是观察角度不同而已。下面程序示范了子类继承父类的特点。下面是 Fruit类的代码。示例代码:inherit.py

class Fruit:    def info(self):        print(f"我是水果!重{self.weight}克" )class Food:    def taste(self):        print("不同食物的口感不同")# 定义Banana类,继承了Fruit和Food类class Banana(Fruit, Food):    pass# 创建Banana对象b = Banana()b.weight = 16# 调用Banana对象的info()方法b.info()# 调用Banana对象的taste()方法b.taste()

这段代码开始定义了两个父类:Fruit类和Food类,接下来程序定义了一个 Banana类,该 Banana类是一个空类。在主程序部分,主程序创建了 Banana对象之后,可以访问Banana对象的info()和 taste()方法,这表明 Banana对象也具有了info和 taste方法,这就是继承的作用:子类扩展(继承)了父类。在子类中将可以继承得到父类定义的方法,这样子类就可复用父类的方法了。2.  关于多继承大部分面向对象的编程语言(除了C++)都只支持单继承,而不支持多继承,这是由于多继承不仅增加了编程的复杂度,而且很容易导致一些莫名的错误。Python虽然在语法上明确支持多继承,但建议如果不是很有必要,则尽量不要使用多继承,而是使用单继承,这样可以保证编程思路更清晰,而且可以避免很多麻烦。当一个子类有多个直接父类时,该子类会继承得到所有父类的方法,这一点在前面代码中已经演示了。现在的问题是,如果多个父类中包含了同名的方法,此时会发生什么呢?此时排在前面的父类中的方法会“遮蔽”排在后面的父类中的同名方法。示例代码:multiple_inherit.py

class Item:    def info (self):        print("Item中方法:", '这是一个商品') class Product:    def info (self):        print("Product中方法:", '这是一个移动产品')class Mouse1(Item, Product):    passclass Mouse2(Product, Item):    passm1 = Mouse1()m1.info()m2 = Mouse2()m2.info()

在这段代码中让 Mouse1继承了Item类和 Product类,Mouse2继承了Product类和Item类,这两个类的父类继承顺序是相反的。由于Mouse1类的Item排在前面,因此Item中定义的方法优先级更高, Python会优先到Item父类中搜寻方法,一旦在Item父类中搜寻到目标方法,Python就不会继续向下搜寻了。上面程序中Item和 Product两个父类中都包含了info()方法,当 Mouse1子类对象调用info方法时,子类中没有定义info方法,因此 Python会从父类中寻找info方法,此时优先使用第1个父类Item中的info方法。而Mouse2子类对象调用的info()方法属于Product类。运行上面程序,将看到如下输出结果:Item中方法: 这是一个商品 Product中方法: 这是一个移动产品3. 重写父类的方法子类扩展了父类,子类是一种特殊的父类。大部分时候,子类总是以父类为基础,额外增加新的方法。但有一种情况例外:子类需要重写父类的方法。例如鸟类都包含了飞翔方法,其中鸵鸟是种特殊的鸟类,因此鸵鸟应该是鸟的子类,它也将从鸟类获得飞翔方法,但这个飞翔方法明显不适合鸵鸟,因此,鸵鸟需要重写鸟类的方法。示例代码:override.py

class Bird:     # Bird类的fly()方法    def fly(self):        print("我在天空里自由自在地飞翔...")class Ostrich(Bird):    # 重写Bird类的fly()方法    def fly(self):        print("我只能在地上奔跑...")  # 创建Ostrich对象os = Ostrich()# 执行Ostrich对象的fly()方法,将输出"我只能在地上奔跑..."os.fly()

运行上面程序,将看到运行os.fly()时执行的不再是Bird类的fly()方法,而是 Ostrich类的fly()方法。这种子类包含与父类同名的方法的现象被称为方法重写(Override),也被称为方法覆盖。可以说子类重写了父类的方法,也可以说子类覆盖了父类的方法。4. 使用未绑定方法调用被重写的方法如果在子类中调用重写之后的方法,Python总是会执行子类重写的方法,不会执行父类中被重写的方法。如果需要在子类中调用父类中被重写的实例方法,那该怎么办呢?读者别忘了,Python类相当于类空间,因此 Python类中的方法本质上相当于类空间内的函数。所以,即使是实例方法,Python也允许通过类名调用。区别在于,在通过类名调用实例方法时,Python不会为实例方法的第1个参数self自动绑定参数值,而是需要程序显式绑定第一个参数self。示例代码:invoke_parent. py

class BaseClass:    def name (self):        print('父类中定义的name方法')class SubClass(BaseClass):    # 重写父类的name方法    def name (self):        print('子类重写父类中的name方法')    def process (self):        print('执行process方法')        # 直接执行name方法,将会调用子类重写之后的name()方法        self.name()        # 使用类名调用实例方法调用父类被重写的方法        BaseClass.name(self)sc = SubClass()sc.process()

上面程序中 SubClass继承了 BaseClass类,并重写了父类的name()方法。接下来程序在 SubClass类中定义了process()方法,该方法直接通过self调用name方法, Python将会执行子类重写之后的name方法。后面的代码通过显式调用 Base_Class 中的name方法,并显式为第1个参数self绑定参数值,这就实现了调用父类中被重写的方法。5.  使用 super函数调用父类的构造方法Python的子类也会继承得到父类的构造方法,如果子类有多个直接父类,那么排在前面的父类的构造方法会被优先使用。例如如下代码:示例代码: super:py

class Employee :    def __init__ (self, salary):        self.salary = salary    def work (self):        print('普通员工正在写代码,工资是:', self.salary)class Customer:    def __init__ (self, favorite, address):        self.favorite = favorite        self.address = address    def info (self):        print(f'我是一个顾客,我的爱好是: {self.favorite},地址是{self.address}' )class Manager1 (Employee,Customer):    passclass Manager2 (Customer, Employee):    passm1 = Manager1(1235)m1.work()m2 = Manager2('服务器', '北京')m2.info()

上面程序中定义了 Manager1类,该类继承了 Employee和 Customer两个父类。接下来程序中的Manager类将会优先使用 Employee类的构造方法(因为它排在前面),所以程序使用Manager(1235)来创建 Manager1对象。该构造方法只会初始化 salary实例变量,因此执行上面程序是没有任何问题的。但如果为Manager2传递一个数值就会引发错误,因为Manager2使用了Customer的构造方法,因此应该使用Manager2('服务器', '北京')创建Manager2对象。为了让 Manager能同时初始化两个父类中的实例变量,Manager应该定义自己的构造方法就是重写父类的构造方法。Python要求:如果子类重写了父类的构造方法,那么子类的构造方法必须调用父类的构造方法。子类的构造方法调用父类的构造方法有两种方式。

  • 使用未绑定方法,这种方式很容易理解。因为构造方法也是实例方法。当然可以通过这种方式来调用;

  • 使用supe()函数调用父类的构造方法;

在交互式解释器中输入help(super)查看 super()函数的帮助信息,可以看到如下输出信息。

class super(object)   super() -> same as super(__class__, )   super(type) -> unbound super object   super(type, obj) -> bound super object; requires isinstance(obj, type)   super(type, type2) -> bound super object; requires issubclass(type2, type)   Typical use to call a cooperative superclass method:   class C(B):       def meth(self, arg):           super().meth(arg)   This works for class methods too:   class C(B):       @classmethod       def cmeth(cls, arg):           super().cmeth(arg)      Methods defined here:      __get__(self, instance, owner, /)       Return an attribute of instance, which is of type owner.      __getattribute__(self, name, /)

从输出的内容可以看出,super其实是一个类,因此调用 super()的本质就是调用 super类的构造方法来创建 super对象。从上面的帮助信息可以看到,使用 super()构造方法最常用的做法就是不传入任何参数(这种做法与 super(type,obj)的效果相同),然后通过 super对象的方法既可调用父类的实例方法,也可调用父类的类方法。在调用父类的实例方法时,程序会完成第1个参数self的自动绑定。现在将上面的代码改成下面的形式:

class Employee :    def __init__ (self, salary):        self.salary = salary    def work (self):        print('普通员工正在写代码,工资是:', self.salary)class Customer:    def __init__ (self, favorite, address):        self.favorite = favorite        self.address = address    def info (self):        print(f'我是一个顾客,我的爱好是: {self.favorite},地址是{self.address}')# Manager继承了Employee、Customerclass Manager(Employee, Customer):    # 重写父类的构造方法    def __init__(self, salary, favorite, address):        print('--Manager的构造方法--')        # 通过super()函数调用父类的构造方法        super().__init__(salary)        # 使用未绑定方法调用父类的构造方法        Customer.__init__(self, favorite, address)# 创建Manager对象m = Manager(25000, 'IT产品', '广州')m.work()m.info()

在这段代码中两行粗体字代码分别示范了两种方式调用父类的构造方法。通过这种方式,Manager类重写了父类的构造方法,并在构造方法中显式调用了父类的两个构造方法执行初始化,这样两个父类中的实例变量都能被初始化。运行上面程序,可以看到如下运行结果:

--Manager的构造方法--普通员工正在写代码,工资是: 25000我是一个顾客,我的爱好是: IT产品,地址是广州

往期回顾:Python编程思想(23):类和对象Python编程思想(24):类的实例方法Python编程思想(25):方法深度解析Python编程思想(26):成员变量对本文感兴趣,可以加李宁老师微信公众号(unitymarvel):

关注  极客起源  公众号,获得更多免费技术视频和文章。

div不继承父类样式_Python编程思想(27):类的继承相关推荐

  1. css不继承父类样式_提升你的Python编程能力,细说类的继承,拿走不谢

    今天咱们聊点啥呢?要不还是聊点Python基础的东东吧,大家已经都知道啦,Python呢是一种面向对象的脚本编程语言,那面向对象的编程语言呢,都会支持面向对象的三大特性,你知道是哪三大特性吗?当然是咱 ...

  2. python class 是否存在某个变量_Python编程思想(29):使用type()函数定义类

    ----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要函 ...

  3. Java类的继承关键字_Java的第八天(类的继承、super关键字的使用、方法的重写)...

    39.类的继承java 描述类的时候,咱们若是发现有几个类有重复的属性和方法,咱们就能够采用继承的方法来设计ide 使用extends关键字来继承this 语法:设计 class 子类 extends ...

  4. div不继承父类样式_Java三大特性之继承

    继承的概念: 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类. 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有 ...

  5. python完全支持面向对象编程思想_面向对象的编程思想和Python的继承和多态,特殊方法,引用计数...

    面向对象的编程思想和Python的类,访问和属性,继承 在上一文中我们了解到了,私有的属性的访问方式:实例名._类名__私有属性名. 一.私有的属性如何对外提供公有的取值和赋值方法呢?提供公有的方法作 ...

  6. 【面向对象编程】(4) 类的继承,重构父类中的方法

    各位同学好,今天和大家分享一下面向对象编程中,类的三大特征之继承.主要介绍:子类继承父类的基本方法:重写父类的类方法:重构父类的初始化方法:super() 方法.本节主要是单继承,多继承在下一节中介绍 ...

  7. python 清空所有对象_Python编程思想(7):列表的增删改操作

    李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要函数库的使用方法.读者可以在「极客起源」 公众号中输入 160 ...

  8. python 类继承 父类初始化_python之子类继承父类时进行初始化的一些问题

    直接看代码: classPerson:def __init__(self): self.name= "jack" classStudent(Person):def __init__ ...

  9. python 静态方法_Python编程思想(25):方法深度解析

    -----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要 ...

最新文章

  1. js填充select下拉框并选择默认值
  2. 打包tomcat没有xml文件_Spring Boot 项目打包 War 并部署到 Tomcat
  3. 当前(2019年)机器学习中有哪些研究方向特别的坑?
  4. 【深度学习】基于深度神经网络进行权重剪枝的算法(二)
  5. 互联网分布式架构--演进过程
  6. 极客精神|自制机械臂!被任正非表扬的华为天才少年
  7. oracle 之 COMMENT
  8. aes加密php源码,AES加解密类源码 · ThinkPHP5高阶实战教程 --诠释为API开发而生 · 看云...
  9. 【Oracle】创建概要文件
  10. 小Q系列故事——大笨钟
  11. 压力换算公斤单位换算_压力与重量换算(公斤换算压力)
  12. 万用表怎么测电池内阻_万用表怎么测量电阻
  13. 【经验分享】BMPR文件及其打开软件Balsamiq Wireframes的下载和安装
  14. 开关电源matlab仿真设计报告,MATLAB非隔离式开关电源仿真分析+源代码
  15. 蓝凌LBPM平台,大公司流程数字化升级必选
  16. 2013, Samara SAU ACM ICPC Quarterfinal Qualification Contest C.Victor‘s Research
  17. eclipse注释出现问号
  18. 前端js实现表格数据的上移下移
  19. 【大数据基础实践】(六)数据仓库Hive的基本操作
  20. python PIL读取图像转换为灰度图及二值图像

热门文章

  1. 学习SharePoint记录,微软给出的的Application Templates很有帮助呢
  2. 订单编号,递增且不连续(php版)
  3. 网络爬虫--7.Handler处理器 和 自定义Opener
  4. 学成在线--16.添加课程计划
  5. Flask爱家租房--房屋管理(搜索房屋列表)
  6. java上传rar文件_java实现上传zip/rar压缩文件,自动解压
  7. Python的Django框架中forms表单类的使用方法详解2
  8. php实现注册登陆验证
  9. 车流检测之halcon光流法算法实现
  10. java 公因数_Java程序(最大公因数与最小公倍数)