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

-----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出《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):

fd74484f542b7a08c3eaa2a7ab22e3d9.png

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

b4d7c287228c9736cb6bd318c6cd14af.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 举例_MySQL 语句举例(一)

举例:有10个用户,输出在订单表中下单数最多的5个人的名字。my_user 表数据my_order,uid对应my_user表的id测试数据生成写一个存储过程,随机插入10000条数据:CREATE DEFINERrootlocalhost PROCEDURE test_loop( )BEGIND…

你知道Linux里D进程会搞事吗?

前言这篇文章是一位大神在实际项目中遇到问题并分析总结出来的,作为新手,能接触到这类文章应该是受益匪浅,这位同学现在在魅族工作,以后也会一直在魅族工作,是Linux 方面的专家,「魅族还有另一个Linux 大神…

react-router 页面离开 提示数据变更

以前项目使用 react-router2.0, 业务层面页面离开的时候需要弹出自己的弹出框,根据用户的操作,进行是否可以离开 试了几种方式都存在问题,实现的并不完美,没办法对用户点击浏览器后退支持的很好,除非是显示…

C语言系列文章之#和##

很久就知道了 # 和 ## ,但是都没怎么使用,直到最近的项目涉及到需要编写大量相似的代码之后才决定尝试使用 ## 去简化代码的书写。比如说我的项目需要控制四个通道的电机,四个通道的逻辑控制代码都是类似的,只是对应的硬件和数据信…

springboot 上传文件_基于SpringBoot的文件上传

在实际的企业开发中,文件上传是最常见的功能之一,SpringBoot集成了SpringMVC常用的功能,当然也包含了文件上传的功能,实现起来没有太多的区别。下面我们来讲解一下,使用SpringBoot如何实现多个文件上传操作。使用的环境…

Linux的 i2c 驱动框架分析

1.基本概念总线设备驱动模型,是Linux 内核的一个基础,基本理论可以说按照大企业的分工原则,每个人只要负责自己的事情,向其他部门给出标准的接口调用,后勤部就负责后勤工作,厨房有可能跟后勤部产生工作上的…

matlab fftshift_数字信号处理没有Matlab?用Python一样很爽

通常,在数字信号处理时,我们避不开matlab这个工具,因其它的强大的功能受到广大工程师的好评,也一直都是业界的不二之选。但是,matlab毕竟是商业软件,公司里如果使用的话,就需要支付高昂的费用。…

栈,C语言实现

什么是数据结构?数据结构是什么?要了解数据结构,我们要先明白数据和结构,数据就是一些int char 这样的变量,这些就是数据,如果你是一个篮球爱好者,那么你的球鞋就是你的数据,结构就是…

Camera摄像头工作原理

回想这工作的这几年,尝尽社会的辛酸艰难,从一开始什么都没有到30万,从30万到200万,从200万到1300万,不是炫耀,我只是想通过我自己的经历告诉我的朋友们「手机像素越高,拍的照片越清晰」摄像头结…

es6一维数组转二维数组_技术图文:Numpy 一维数组 VS. Pandas Series

背景Numpy 提供的最重要的数据结构是 ndarray,它是 Python 中 list 的扩展。Pandas 提供了两种非常重要的数据结构 Series和DataFrame。Numpy 中的一维数组与 Series 相似,一维数组只是提供了从0开始与位置有关的索引,而Series除了位置索引之…

unity UI事件

由于工作需要到持续按键,所以了解了一下unity UI事件,本文主要转载于http://www.cnblogs.com/zou90512/p/3995932.html?utm_sourcetuicool&utm_mediumreferral,并对相关问题进行解释。 我们最常用到的就是unity的button组件,…

电子工程学院的师兄弟姐们们,老师叫你们回家

昨天写了很长的文章,接收到推送的同学们应该也会很开心,但是由于我的原因,需要把文章删除「你们能想到的原因肯定不是我删文的原因」,但是呢,也因为这样,又可以重写一篇,刚好可以多加点内容。后…

auto.js停止所有线程_Java多线程编程基础知识 概念介绍,以及线程状态

一、进程进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动。操作系统中,几乎所有运行中的任务对应一条进程(Process)。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中…

Linux 进程管理数据结构

文末集赞留言抽奖,我会选出留言点赞数前 3 名送出小米耳机。别刷赞啊,刷赞被举报无效,相信真的是公众号粉丝的读者,不会做这样的行为,刷赞指的是购买外挂刷,如果是转发到朋友圈和微信群的,不算刷…

如何安装python3.8_python3.8下载及安装步骤详解

1.操作系统:Windows7 64bit executable installer 2.安装步骤: 双击安装文件python-3.8.0-amd64.exe 勾选下方“Add Python 3.8 to PATH”,并选择“Customize installation”3.把Optional Features全部勾选上,点击“Next"4.A…

队列,C语言实现

什么是队列?上一篇文章写了什么是栈,用C语言实现了栈,既然说了栈,不说队列,感觉总是少了点什么,所以就顺手写一个队列,而且最近做项目也用到这个队列的代码。栈的特点是先进后出,队列…

华为hr,我尽力了

最近,一则新闻很火但是突然,又不火了,火于不火之间,时间有点短,其中猜测很大部分是gongguan原因以下为正文截图~以上为事件原文,这个是一个热点新闻,之前发了一个热点新闻,瞬间就火爆…

idea,eclipse创建多模块项目

新建一个maven项目 iead,新建是不选择archetype,新建好之后,pom中的 <packaging>pom</packaging>节点是默认的,如果不是要改成这这样子 然后选中这个项目,新建一个module,之后就和建立普通项目一样了. eclipse 是这样的 建一个普通的maven项目就可以了 这个是建好之…

python画图程序代码_少儿python编程(7)海龟画图(拓展1)

我们继续用Python的海龟库来画图吧&#xff01;上图是画一朵花的程序&#xff0c;重点是6-12行&#xff0c;使用了函数来定义drawleaf:每一掰叶子由两条弧线组成&#xff0c;每一条弧线重复画15次&#xff0c;每次前进5步&#xff0c;右转6度。看图形化代码就很清楚了&#xff…

opencv matlab三维点云,点云采样的三种方法 - 小白学视觉的个人空间 - OSCHINA - 中文开源技术交流社区...

点击上方“小白学视觉”&#xff0c;选择“星标”公众号重磅干货&#xff0c;第一时间送达编辑&#xff1a;3D视觉工坊本文由知乎作者GeometryHub授权转载&#xff0c;不得擅自二次转载。原文链接&#xff1a;https://zhuanlan.zhihu.com/p/86044055点云采样分类点云采样的方法…