面向对象之:继承

一:什么面向对象的继承?     

比较官方的说法就是:

继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。

字面意思就是:子承父业,合法继承家产,就是如果你是独生子,而且你也很孝顺,不出意外,你会继承你父母所有家产,他们的所有财产都会由你使用(败家子儿除外)。

那么用一个例子来看一下继承:

class Person:def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sexclass Cat:def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sexclass Dog:def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sex# 继承的用法:
class Aniaml(object):def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sexclass Person(Aniaml):passclass Cat(Aniaml):passclass Dog(Aniaml):pass
继承

继承的优点也是显而易见的:

1,增加了类的耦合性(耦合性不宜多,宜精)。

2,减少了重复代码。

3,使得代码更加规范化,合理化。

二 继承的分类。                         

就向上面的例子:

Aminal 叫做父类,基类,超类。
Person Cat Dog: 子类,派生类。
继承:可以分单继承,多继承

这里需要补充一下python中类的种类(继承需要):

在python2x版本中存在两种类.:
  ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
  ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

三,单继承。                         

3.1 类名,对象执行父类方法       

class Aniaml(object):type_name = '动物类'def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sexdef eat(self):print(self)print('吃东西')class Person(Aniaml):passclass Cat(Aniaml):passclass Dog(Aniaml):pass# 类名:
print(Person.type_name)  # 可以调用父类的属性,方法。
Person.eat(111)
print(Person.type_name)# 对象:
# 实例化对象
p1 = Person('春哥','',18)
print(p1.__dict__)
# 对象执行类的父类的属性,方法。
print(p1.type_name)
p1.type_name = '666'
print(p1)
p1.eat()
类名,对象分别调用父类方法

3.2 执行顺序                               

class Aniaml(object):type_name = '动物类'def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sexdef eat(self):print(self)print('吃东西')class Person(Aniaml):def eat(self):print('%s 吃饭'%self.name)class Cat(Aniaml):passclass Dog(Aniaml):passp1 = Person('barry','',18)
# 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
p1.eat()
# 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
执行顺序

3.3同时执行类以及父类方法      

方法一:

如果想执行父类的func方法,这个方法并且子类中也用,那么就在子类的方法中写上:

父类.func(对象,其他参数)

举例说明:

class Aniaml(object):type_name = '动物类'def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sexdef eat(self):print('吃东西')class Person(Aniaml):def __init__(self,name,sex,age,mind):'''self = p1name = '春哥'sex = 'laddboy'age = 18mind = '有思想''''# Aniaml.__init__(self,name,sex,age)  # 方法一self.mind = minddef eat(self):super().eat()print('%s 吃饭'%self.name)
class Cat(Aniaml):passclass Dog(Aniaml):pass# 方法一: Aniaml.__init__(self,name,sex,age)
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)# 对于方法一如果不理解:
# def func(self):
#     print(self)
# self = 3
# func(self)

方法二:

利用super,super().func(参数)

class Aniaml(object):type_name = '动物类'def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sexdef eat(self):print('吃东西')class Person(Aniaml):def __init__(self,name,sex,age,mind):'''self = p1name = '春哥'sex = 'laddboy'age = 18mind = '有思想''''# super(Person,self).__init__(name,sex,age)  # 方法二super().__init__(name,sex,age)  # 方法二self.mind = minddef eat(self):super().eat()print('%s 吃饭'%self.name)
class Cat(Aniaml):passclass Dog(Aniaml):pass
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)

总结:子类执行父类方法

在子类中,执行父类的方法
Animal.__init__(self,name,sex,age)  # 第一种
用这种: super().__init__(name, sex, age)  # 第二种  
完整的写法 super(Person,self).__init__(name, age, sex) 不提倡 第二种#完整的写法

单继承练习题:

# 1
class Base:def __init__(self, num):self.num = numdef func1(self):print(self.num)class Foo(Base):pass
obj = Foo(123)
obj.func1() # 123 运⾏的是Base中的func1  # 2      
class Base:def __init__(self, num):self.num = numdef func1(self):print(self.num)
class Foo(Base):def func1(self):print("Foo. func1", self.num)
obj = Foo(123)
obj.func1() # Foo. func1 123 运⾏的是Foo中的func1       # 3         
class Base:def __init__(self, num):self.num = numdef func1(self):print(self.num)
class Foo(Base):def func1(self):print("Foo. func1", self.num)
obj = Foo(123)
obj.func1() # Foo. func1 123 运⾏的是Foo中的func1     
# 4
class Base:def __init__(self, num):self.num = numdef func1(self):print(self.num)self.func2()def func2(self):print("Base.func2")
class Foo(Base):def func2(self):print("Foo.func2")
obj = Foo(123)
obj.func1() # 123 Foo.func2 func1是Base中的 func2是⼦类中的 
# 再来
class Base:def __init__(self, num):self.num = numdef func1(self):print(self.num)self.func2()def func2(self):print(111, self.num)
class Foo(Base):def func2(self):print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:obj.func2() # 111 1 | 111 2 | 222 3# 再来
class Base:def __init__(self, num):self.num = numdef func1(self):print(self.num)self.func2()def func2(self):print(111, self.num)
class Foo(Base):def func2(self):print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:obj.func1() # 那笔来吧. 好好算# 1
#111 1
# 2
# 111 2
# 3
# 222 3
View Code

四,多继承                                                    

class ShenXian: # 神仙def fei(self):print("神仙都会⻜")
class Monkey: #def chitao(self):print("猴⼦喜欢吃桃⼦")
class SunWukong(ShenXian, Monkey): # 孙悟空是神仙, 同时也是⼀只猴pass
sxz = SunWukong() # 孙悟空
sxz.chitao() # 会吃桃⼦
sxz.fei() # 会⻜

此时, 孙悟空是⼀只猴⼦, 同时也是⼀个神仙. 那孙悟空继承了这两个类. 孙悟空⾃然就可以执⾏这两个类中的⽅法. 多继承⽤起来简单. 也很好理解. 但是多继承中, 存在着这样⼀个问题. 当两个⽗类中出现了重名⽅法的时候. 这时该怎么办呢? 这时就涉及到如何查找⽗类⽅法的这么⼀个问题.即MRO(method resolution order) 问题. 在python中这是⼀个很复杂的问题. 因为在不同的python版本中使⽤的是不同的算法来完成MRO的.

这里需要补充一下python中类的种类(继承需要):

在python2x版本中存在两种类.:
  ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
  ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

4.1经典类的多继承         

虽然在python3中已经不存在经典类了. 但是经典类的MRO最好还是学⼀学. 这是⼀种树形结构遍历的⼀个最直接的案例. 在python的继承体系中. 我们可以把类与类继承关系化成⼀个树形结构的图. 来, 上代码:

class A:pass
class B(A):pass
class C(A):pass
class D(B, C):pass
class E:pass
class F(D, E):pass
class G(F, D):pass
class H:pass
class Foo(H, G):pass
代码示例

对付这种mro画图就可以:

继承关系图已经有了. 那如何进⾏查找呢? 记住⼀个原则. 在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个.

图中每个圈都是准备要送鸡蛋的住址. 箭头和⿊线表⽰线路. 那送鸡蛋的顺序告诉你入⼝在最下⾯R. 并且必须从左往右送. 那怎么送呢?

如图. 肯定是按照123456这样的顺序来送. 那这样的顺序就叫深度优先遍历. ⽽如果是142356呢? 这种被称为⼴度优先遍历. 好了. 深度优先就说这么多. 那么上⾯那个图怎么找的呢? MRO是什么呢? 很简单. 记住. 从头开始. 从左往右. ⼀条路跑到头, 然后回头. 继续⼀条路跑到头. 就是经典类的MRO算法. 

类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C. 你猜对了么?

4.2新式类的多继承          

4.2.1 mro序列

MRO是一个有序列表L,在类被创建时就计算出来。
通用计算公式为:

mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
(其中Child继承自Base1, Base2)

如果继承至一个基类:class B(A) 
这时B的mro序列为

mro( B ) = mro( B(A) )
= [B] + merge( mro(A) + [A] )
= [B] + merge( [A] + [A] )
= [B,A]

如果继承至多个基类:class B(A1, A2, A3 …) 
这时B的mro序列

mro(B) = mro( B(A1, A2, A3 …) )
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
= ...

计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。

4.2.2. 表头和表尾
表头: 
  列表的第一个元素

表尾: 
  列表中表头以外的元素集合(可以为空)

示例 
  列表:[A, B, C] 
  表头是A,表尾是B和C

4.2.3. 列表之间的+操作
+操作:

[A] + [B] = [A, B]
(以下的计算中默认省略)
---------------------

merge操作示例:

如计算merge( [E,O], [C,E,F,O], [C] )
有三个列表 :  ①      ②          ③1 merge不为空,取出第一个列表列表①的表头E,进行判断                              各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
2 取出列表②的表头C,进行判断C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
3 进行下一次新的merge操作 ......
--------------------- 

 计算mro(A)方式:

mro(A) = mro( A(B,C) )原式= [A] + merge( mro(B),mro(C),[B,C] )mro(B) = mro( B(D,E) )= [B] + merge( mro(D), mro(E), [D,E] )  # 多继承= [B] + merge( [D,O] , [E,O] , [D,E] )  # 单继承mro(D(O))=[D,O]= [B,D] + merge( [O] , [E,O]  ,  [E] )  # 拿出并删除D= [B,D,E] + merge([O] ,  [O])= [B,D,E,O]mro(C) = mro( C(E,F) )= [C] + merge( mro(E), mro(F), [E,F] )= [C] + merge( [E,O] , [F,O] , [E,F] )= [C,E] + merge( [O] , [F,O]  ,  [F] )  # 跳过O,拿出并删除= [C,E,F] + merge([O] ,  [O])= [C,E,F,O]原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])= [A,B] + merge( [D,E,O], [C,E,F,O],   [C])= [A,B,D] + merge( [E,O], [C,E,F,O],   [C])  # 跳过E= [A,B,D,C] + merge([E,O],  [E,F,O])= [A,B,D,C,E] + merge([O],    [F,O])  # 跳过O= [A,B,D,C,E,F] + merge([O],    [O])= [A,B,D,C,E,F,O]
--------------------- 

这个说完了. 那C3到底怎么看更容易呢? 其实很简单. C3是把我们多个类产⽣的共同继
承留到最后去找. 所以. 我们也可以从图上来看到相关的规律. 这个要⼤家⾃⼰多写多画图就
能感觉到了. 但是如果没有所谓的共同继承关系. 那⼏乎就当成是深度遍历就可以了

 

转载于:https://www.cnblogs.com/ls13691357174/p/10476057.html

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

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

相关文章

7用Eclipse进行JSP开发

用Eclipse进行JSP开发 Eclipse简介和下载 Eclipse的发展 什么是Eclipse Eclipse下载 用Eclipse进行JSP开发 软件环境配置 安装JDK,配置Java运行环境 安装Tomcat服务器(服务器能够正常启动和关闭) 安装Eclipse JSP开发

求递归算法时间复杂度:递归树

引用自:http://www.cnblogs.com/wu8685/archive/2010/12/21/1912347.html 递归算法时间复杂度的计算方程式一个递归方程: 在引入递归树之前可以考虑一个例子: T(n) 2T(n/2) n2 迭代2次可以得: T(n) n2 2(2T(n/4) (n/2) 2) 还…

[Leetcode][JAVA]第[29]题[两数相除][二分法]

【问题描述】[中等] 给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。返回被除数 dividend 除以除数 divisor 得到的商。整数除法的结果应当截去(truncate)其小数部分,…

8.用MyEclipse进行JSP开发

用MyEclipse进行JSP开发

Hihocoer 1336 - Matrix Sum 二维树状数组

题意 给我们个n*n的矩阵 有m个操作让我们 操作有两种 Add x y v对(x,y)上的元素加v Sum x1 y1 x2 y2 对(x1,y1)为左上角(x2,y2)为右下角的矩阵求和并mod 1e97 初始矩阵每个元素都是0 1 ≤ N ≤ 1000, 1 ≤ M ≤ 100000 For each Add operation: 0 ≤ x < N, 0 ≤ y < N…

Java学习笔记13-1——SpringMVC

文章目录1.什么是MVC回顾Servlet2.什么是SpringMVC概述中心控制器SpringMVC执行原理3.第一个SpringMVC 程序使用XML配置实现使用注解实现4.控制器和RestFul风格控制器Controller实现Controller接口使用注解ControllerRequestMappingRestFul 风格扩展&#xff1a;小黄鸭调试法5.…

端口占用怎么查找

D:\Users\hp\Documents\NetBeansProjects\WebApplication1\nbproject\build-impl.xml:1030: Deployment error: Starting of Tomcat failed, the server port 8080 is already in use. netstat -aon|findstr "8080" 查看端口 查看端口的进程 记住3306 tasklist|fi…

数据库相关

https://blog.csdn.net/qq_35246620/article/details/70823903 瞻仰大佬的博客,,学习学习 转载于:https://www.cnblogs.com/wangxiaoshou/p/10483428.html

eclipse没有server怎么办

1打开eclipse 找到help 2点开&#xff0c;查找 Install new software 二步、然后在Work with中点击Add&#xff0c;如下图所示&#xff0c;加入Name"Kepler" repository&#xff1b;Locationhttp://download.eclipse.org/releases/kepler。 3填写完成后使用add 4第…

HDU - 5441 Travel 离线处理+并查集

题意 给我们一个图 给出这个图的n个点 和m个边和权值 然后再分别给我们q个查询 每个查询给一个x 让我们在这个图中找出多少个不同的有序对 使得从x到y的最大权值不超过x n≤20000,m≤100000,q≤5000. 分析 20000个点 1000ms 暴力肯定不行 看似这道题像是个图论的题 嘿嘿嘿 其…

zabbix利用SNMPTrap接收交换机主动告警

zabbix接收trap的工作流程&#xff1a; snmptrapd 收到trapsnmptrapd将trap传递给SNMPTT或调用Perl接收器SNMPTT或Perl trap接收器解析&#xff0c;格式化并将trap写入文件Zabbix SNMP trap读取并解析trap文件对于每个trap&#xff0c;Zabbix发现主机接口与接收的trap地址匹配的…

eclipse安装jsp

1打开window中preferences 2找到server下runningtime 3add 4选择 5加入 6找到 7建立一个新jsp文件

03-java学习-基本数据类型-运算符-键盘接收用户输入

java的八大基本数据类型&#xff1a; 类型转换的基本原则&#xff1a; java整数的默认类型是int&#xff0c;小数的默认类型是double 运算符&#xff1a; 算术运算符、连接、赋值、关系、逻辑、三目运算符等…… 键盘接收用户输入&#xff1a; java.util.Scanner类的了解和使用…

POJ-1651 Multiplication Puzzle 矩阵连乘问题(区间dp)

题意 给我们n个数 让我们随意的跳出其中的数 每挑出一个数 计算代价为左边数* 当前数 * 右边的数 除了首尾两个数不选 中间的数可以任意挑 让我们求最小代价 CODE #include<bits/stdc.h> using namespace std; int a[110],m[110][110]; const int maxn 0x7f7f7f; in…

The Apache Tomcat installation at this directory is version,tomcat

The Apache Tomcat installation at this directory is version,tomcat版本号过高eclipse无法导入解决办法 找到tomcat安装位置进入lib目录 lib目录下有个catalina.jar 用解压缩软件打开 打开后 在catalina.jar\org\apache\catalina\util目…

9.JSP运行原理与JSP页面的基本结构

JSP运行原理与JSP页面的基本结构 HTML页面的基本构成 .代码中出现的几种标签 •单标签 某些标签只需单独使用就能完整地表达意思&#xff0c;控制网页 效果&#xff0c;这类标签的语法是&#xff1a; <标签> 双标签 标签成对使用&#xff0c;由一个开始标签和一个结…

给定两个整数m和n,求出m~n这段连续的整数中所有偶数的平方和以及所有奇数的立方和。

//自己留着复习用 #include<stdio.h> int s(int a) { if (a%20) return aa; else return aa*a;} int main () {int i,m,n,s1,s2; scanf("%d %d",&m,&n);s1s20; for(im;i<n;i) { if(i%20) s1s1s(i); else s2s2s(i);} printf("%d %d",s…

[Leedcode][JAVA][第124题][二叉树中的最大路径和][递归][二叉树]

【问题描述】[困难] 给定一个非空二叉树&#xff0c;返回其最大路径和。本题中&#xff0c;路径被定义为一条从树中任意节点出发&#xff0c;达到任意节点的序列。该路径至少包含一个节点&#xff0c;且不一定经过根节点。示例 1:输入: [1,2,3]1/ \2 3输出: 6 示例 2:输入: …

SAS对数据变量的处理

SAS对数据变量的处理 在使用DATA步基于已经存在的数据集生成新数据集时&#xff0c;可以指定在新数据集中不需要包含的变量而仅读取其他变量&#xff0c;或者指定仅需要在 新数据集中包含的变量。该功能可以通过DATA步中的SET语句和数据集选项KEEP和DROP来实现&#xff0c;也可…