继承进阶

先讲一个例子:

#老师有生日,怎么组合哪?
class Birthday:  # 生日def __init__(self,year,month,day):self.year = yearself.month = monthself.day = dayclass Teacher:  # 老师<br>def __init__(self,name,birth):self.name = nameself.birthday = birthalex = Teacher('alex','2018-7-14')
print(alex.birthday)# 2018-7-14#但是这么传日期不好,需要分开,使用组合方式:
class Birthday:def __init__(self,year,month,day):self.year = yearself.month = monthself.day = dayclass Teacher:def __init__(self,name,birth):self.name = nameself.birthday = birthbirth = Birthday(2018,7,14)
alex = Teacher('alex',birth)   # 用实例建立桥梁
print(birth.year)
print(alex.birthday.year)  # 调用组合对象中的属性# 输出结果
2018
2018
2018-7-14

Teacher 也可以定义一个方法,执行Birthday类里面的方法:

class Birthday:def __init__(self,year,month,day):self.year = yearself.month = monthself.day = daydef fmt(self):return '%s-%s-%s'%(self.year,self.month,self.day)class Teacher:def __init__(self,name,birth):self.name = nameself.birthday = birthdef birth_month(self):   #算盘打到家了return self.birthday.fmt()  # 引用组合对象的方法
 
birth = Birthday(2018,7,14)
alex = Teacher('alex',birth)
print(birth.year)
print(alex.birthday.year)  # 调用组合对象中的属性
print(alex.birthday.fmt())  # 调用组合对象中的方法,要加括号
print(alex.birth_month())#运行结果:
2018
2018
2018-7-14
2018-7-14

  总结: 组合就是一个对象引用另一个对象,用它的方法。

继承的类:父类、基类、超类

想继承的类:子类、派生类

 


 

讲一个继承的例子:

  猫
  属性 性别 品种
  方法 吃 喝 爬树

  狗
  属性 性别 品种
  方法 吃 喝 看门

从上面可以看出,狗和猫有共同的属性和方法,唯独有一个方法是不一样的。
那么是否可以继承呢?

class Animal:  # 动物def __init__(self,name,sex,kind):self.name = nameself.sex = sexself.kind = kinddef eat(self):  #print('%s is eating'%self.name)def drink(self):  #print('%s is drinking'%self.name)class Cat(Animal):  #def climb(self):  # 爬树print('%s is climbing'%self.name)class Dog(Animal):  #def watch_door(self):  # 看门print('%s is watching door'%self.name)tom = Cat('tom','','招财猫')   # 实例化对象
hake = Dog('hake','','藏獒')
print(Cat.__dict__)   # Cat.__dict__ Cat类的命名空间中的所有名字
print(tom.__dict__)   # tom.__dict__ 对象的命名空间中的所有名字
tom.eat()   # 先找自己对象的内存空间 再找类的空间 再找父类的空间
tom.climb()   # 先找自己的内存空间 再找类的空间#运行结果:
{'__doc__': None, 'climb': <function Cat.climb at 0x000001C95178AAE8>, '__module__': '__main__'}
{'sex': '', 'name': 'tom', 'kind': '招财猫'}
tom is eating
tom is climbing

  


 

一、Object类

class A:pass
A()

#实例化的过程

  1.创建一个空对象
  2.调用init方法  其实A是继承的object,而其初识函数是空的
  3.将初始化之后的对象返回调用处

  以上代码,A调用了init方法了?答案是:调用了! 这是什么调用,调用了object类的初始化函数

所有的类都继承了object类

  查看object的源码,可以找到__init__方法:

def __init__(self): # known special case of object.__init__""" Initialize self.  See help(type(self)) for accurate signature. """pass既然A继承了object类,那么它肯定执行了父类object的__init__方法
加一段注释class A:'''这是一个类'''passa = A()
print(A.__dict__)  # 双下方法 魔术方法
#运行结果:{'__doc__': '\n 这是一个类\n ', '__module__': '__main__', '__dict__':
<attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__'
of 'A' objects>}

  可以在上面的结果中找到两个带object的方法,很明显这就是调用了object类!

总结:

  任何类实例化都经历3步,如果类没有init,由object完成了。


 

 class Parent:passclass Son(Parent):passprint(Son.__bases__)  # (<class '__main__.Parent'>,)class Parent1:pass
class Parent2:passclass Son(Parent1,Parent2):passprint(Son.__bases__)   # (<class '__main__.Parent1'>, <class'__main__.Parent2'>)
__bases__的用法

 

二、单继承:

  比如人工大战,人类和狗有共同属性,比如名字,血量,攻击了。还有共同的方法吃药:

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻击力def eat(self):print('%s吃药回血了' % self.name)class Person(Animal):def attack(self,dog):  # 派生类print('%s攻击了%s' %(self.name,dog.name))class Dog(Animal):def bite(self,person):  # 派生类print('%s咬了%s' %(self.name,person.name))alex = Person('alex',100,10)
print(alex.__dict__)#执行输出:{'ad': 10, 'hp': 100, 'name': 'alex'}

但是还有不同的,比如人类有性别,狗类有品种怎么么办哪?可以在子类init里面加属#Person增加init方法

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻击力def eat(self):print('%s吃药回血了' % self.name)class Person(Animal):def __init__(self,sex):self.sex = sexdef attack(self,dog):  # 派生类print('%s攻击了%s' %(self.name,dog.name))class Dog(Animal):def __init__(self,kind):self.kind = kinddef bite(self,person):  # 派生类print('%s咬了%s' %(self.name,person.name))
# 人 sex
alex = Person('alex')  # 此时只能传一个参数,否则报错
print(alex.__dict__)

#执行输出: {'sex': 'alex'}

  发现和上面的例子少了一些属性,animal继承的属性都没有了。what?
因为子类自己有init方法了,它不会执行父类的init方法
那么如何执行父类的init呢?同时保证自己的init方法也能执行?

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻击力def eat(self):print('%s吃药回血了' % self.name)class Person(Animal):def __init__(self,name,hp,ad,sex): Animal.__init__(self,name,hp,ad)  # 执行父类方法 也可以使用super().__init__(name,hp,ad),它不需要self参数,
super(Person,self).__init__(name,hp,ad)
self.sex = sexdef attack(self,dog): # 派生类print('%s攻击了%s' %(self.name,dog.name))class Dog(Animal):def __init__(self,name,hp,ad,kind):Animal.__init__(self, name, hp, ad)self.kind = kinddef bite(self,person): # 派生类print('%s咬了%s' %(self.name,person.name))# 人 sex alex = Person('alex',100,10,'female') # 实例化 print(alex.__dict__)执行输出: {'ad': 10, 'name': 'alex', 'hp': 100, 'sex': 'female'}

 

四、多继承

 

  多继承和单继承是一样的
  如果对象使用名字是子类中有的,那么一定用子类的
  子类没有,可以到多个父类中去寻找,问题来了,继承谁的那?

class FlyAnimal:def fly(self):pass
class SwimAnimal:def swim(self):passdef eat():pass
class WalkAnimal:def walk(self):passdef eat():passclass Frog(SwimAnimal,WalkAnimal): pass
class Tiger(SwimAnimal,WalkAnimal):pass
class Swan(FlyAnimal,SwimAnimal,WalkAnimal):pass
class Parrot(FlyAnimal,WalkAnimal):def talk(self):pass
多继承例子

 

 

 


 

三、super方法

  Animal.__init__(self, name, hp, ad) 是直接使用类名.方法名 这样执行的。

第二种写法,使用super:

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻击力def eat(self):  # 吃药print('%s吃药回血了' % self.name)<br>        self.hp += 20class Person(Animal):def __init__(self,name,hp,ad,sex):#Animal.__init__(self,name,hp,ad)  # 执行父类方法 # super(Person,self).__init__(name,hp,ad)   # 完整写法.在单继承中,super负责找到
当前类所在的父类,在这个时候不需要再手动传selfsuper().__init__(name, hp, ad) # 简写.效果同上。它不需要传参数Person,self。
因为它本来就在类里面,自动获取参数
self.sex = sexdef attack(self,dog): # 派生类print('%s攻击了%s' %(self.name,dog.name))class Dog(Animal):def __init__(self,name,hp,ad,kind):super().__init__(name, hp, ad)self.kind = kinddef bite(self,person): # 派生类print('%s咬了%s' %(self.name,person.name))# 人 sex alex = Person('alex',100,10,'female') # 实例化 print(alex.__dict__)#执行输出: {'ad': 10, 'name': 'alex', 'hp': 100, 'sex': 'female'}类外层调用eat方法: #父类有eat,子类没有 alex.eat() #找父类 执行输出: alex吃药回血了

  比如人吃药要扣钱,狗吃药,不要钱。在Animal类中,eat方法,执行时,没有扣钱。

那么就需要在人类中添加eat方法,定义扣钱动作。

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻击力def eat(self):print('%s吃药回血了' % self.name)class Person(Animal):def __init__(self,name,hp,ad,sex):#Animal.__init__(self,name,hp,ad)  # 执行父类方法# super(Person,self).__init__(name,hp,ad)   # 完整写法.在单继承中,super负责找到当前类所在的父类,在这个时候不需要再手动传selfsuper().__init__(name, hp, ad)  # 简写.效果同上。它不需要传参数Person,self。因为它本来就在类里面,自动获取参数self.sex = sex  # 性别self.money = 0  # 增加默认属性moneydef attack(self,dog):  # 派生类print('%s攻击了%s' %(self.name,dog.name))def eat(self):  # 重新定义eat方法super().eat()  # 执行父类方法eatprint('eating in Person')self.money -= 50  # 扣钱
class Dog(Animal):def __init__(self,name,hp,ad,kind):super().__init__(name, hp, ad)self.kind = kinddef bite(self,person):  # 派生类print('%s咬了%s' %(self.name,person.name))# 人 sex
alex = Person('alex',100,10,'female')   # 实例化
alex.eat()  # 子类有eat 不管父类中有没有,都执行子类的#执行结果:
# 人 sex
alex = Person('alex',100,10,'female')   # 实例化
alex.eat()  # 子类有eat 不管父类中有没有,都执行子类的

  # 总结:父类方法,如果子类有个性化需求,可以重新定义次方法。

在类外面

当子类中有,但是想要调父类的。

alex = Person('alex',100,10,'female')   # 实例化
Animal.eat(alex)  # 指名道姓
super(Person,alex).eat()  # 效果同上,super(子类名,子类对象)方法,一般不用#执行输出:
alex吃药回血了
alex吃药回血了 

一般不会在类外面,执行super方法。都是在类里面调用父类方法super是帮助寻找父类的在外部,super没有简写。

 


 

四、钻石继承

  父类是新式类,那么子类全是新式类,同理经典类也一样。在python3里面没有经典类。

多继承:

这个形状,像钻石一样,老外喜欢浪漫,有些书籍写的叫钻石继承,代码如下:

class A:def func(self):print('A')
class B(A):def func(self):print('B')
class C(A):def func(self):print('C')
class D(B,C):def func(self):print('D')d = D()
d.func()#执行输出:D

#然而,把D的代码注释
 
class D(B,C):
  pass
  #def func(self):
    print('D')

#运行结果:B

#把B的代码注释:
  class B(A):
    pass
    # def func(self):
        print('B')

#执行输出: C

#把C的代码注释:
  class C(A):
    pass
    # def func(self):
        print('C')

#执行输出:A

 


 

 广度优化 :

1.如果从左到右第一个类,
2.在后面的继承顺序中也是第一个,或者不再出现在后面的继承顺序中
3.那么就可以把这个点提取出来,作为继承顺序中的第一个类
广度优先规则

 

广度优先搜索算法(英语:Breadth-First-Search,缩写为BFS),又译作宽度优先搜索,或横向优先搜索,是一种图形搜索算法。简单的说,

BFS是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。

  也就是第一次不走到头,头可能被多个对象继承,如A,从最后一个引用的类进入A

看图,查看顺序:

 

再看一个龟壳模型:

代码如下:

class A:def func(self):print('A')
class B(A):passdef func(self):print('B')
class C(A):passdef func(self):print('C')
class D(B):passdef func(self):print('D')
class E(C):passdef func(self):print('E')
class F(D,E):passdef func(self):print('F')f = F()
f.func()

#执行输出: F

 

看图,查看顺序:

# 在python2中还有深度优先,就是第一次会取到最深处,F->D->B->A->E->C。

在这个例子中,A为顶点,因为有2个类继承了A

在执行第3步时,由于B继承了A,B并没有直接去找A。而是在这这一层中断查找。

由同层的E去查找,然后到C,最后到A,这就是广度优先算法

 注意:在广度优先算法中,Python直接提供了方法mro,可以查看搜索循环:

f = F()
f.func()
print(F.mro())   #需要注意的是super始终是遵循mro的#执行输出:#通过mro可以查看顺序
F
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

 #总结: 新式类 多继承 寻找名字的顺序,遵循广度优先(mro)!

 经典面试题:

class A:def func(self):print('A')
class B(A):def func(self):super().func()print('B')
class C(A):def func(self):super().func()print('C')
class D(B,C):def func(self):super().func()print('D')d = D()
d.func()#执行结果:   在D(B,C)中先看B中,再看C,从C到A
A
C
B
D

在上的例子中,super不是找父类的,它是找下一个节点的

遇到多继承和super

    对象.方法

        找到这个对象对应的类

        将这个类的所有父类都找到画成一个图

        根据图写出广度优先的顺序

        再看代码,看代码的时候,要根据广度优先顺序图来找对应的super 

    总结:super():

        1、在单继承中就是单纯得寻找父类

        2、在多继承中就是根据子节点 通过mro循环寻找下一个类


 

深度优化  :只在Python2中,且没有继承object,没有mro和super方法

一条路走到黑
深度优先规则

 

  所谓深度优化是“一路摸到黑”,也就是说深度优化搜索会不假思索地一直扩展一个状态直到到达不能被扩展的叶子状态。

要用到Python2测试,代码如下:

class A:def func(self):print('A')
class B(A):def func(self):print('B')
class C(A):def func(self):print('C')
class D(B,C):def func(self):print('D')d = D()
d.func()#执行结果: D

在Python2里面,不手动继承Object,比如class A(object)就是经典类,比如calss A,在例子中B继承了A,B在去找A,执行输出A

 

顺序如图: 

 

  深度优化,一条路走到黑,找不到,就回来找其他的

 

 总结:

  经典类:在Python2.*版本才存在,且必须不继承object

     1、遍历的时候遵循深度优化算法

      2、没有mro() 和 super()方法

  新式类: 在Python2.*版本中,需要继承object才是新式类

     1、遍历的时候遵循广度优先算法

     2、在新式类中,有mro方法,同时也有super方法,但是在2.*版本中,必须传参数(子类名,子类对象)

 

转载于:https://www.cnblogs.com/double-W/p/9784799.html

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

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

相关文章

PCM接口详细介绍--TDM方式

1. 概述 PCM = Pulse Code Modulation 是通过等时间隔(即采样率时钟周期)采样将模拟信号数字化的方法。图为4 bit 采样深度的PCM数据量化示意图: PCM数字音频接口,说明接口传输的音频数据是通过PCM方式采样得到的,区别于PDM形式;IIS传输的也是PCM类型数据,属于其一个特…

Kconfig文件结构(图文)简介

1 Kconfig和Makefile 毫不夸张地说&#xff0c;Kconfig和Makefile是我们浏览内核代码时最为依仗的两个文件。基本上&#xff0c;Linux 内核中每一个目录下边都会有一个Kconfig文件和一个Makefile文件。Kconfig和Makefile就好似一个城市的地图&#xff0c;地图引导我们去 认识一…

PDM接口介绍

1. 概述 PDM Pulse Density Modulation是一种用数字信号表示模拟信号的调制方法。 PDM则使用远高于PCM采样率的时钟采样调制模拟分量&#xff0c;只有1位输出&#xff0c;要么为0&#xff0c;要么为1。因此通过PDM方式表示的数字音频也被称为Oversampled 1-bit Audio。相比P…

Kaggle 泰坦尼克

入门kaggle&#xff0c;开始机器学习应用之旅。 参看一些入门的博客&#xff0c;感觉pandas&#xff0c;sklearn需要熟练掌握&#xff0c;同时也学到了一些很有用的tricks&#xff0c;包括数据分析和机器学习的知识点。下面记录一些有趣的数据分析方法和一个自己撸的小程序。 1…

语音交互设备 前端信号处理技术和语音交互过程介绍

一、前端信号处理 1. 语音检测&#xff08;VAD&#xff09; 语音检测&#xff08;英文一般称为 Voice Activity Detection&#xff0c;VAD&#xff09;的目标是&#xff0c;准确的检测出音频信号的语音段起始位置&#xff0c;从而分离出语音段和非语音段&#xff08;静音或噪…

【BZOJ1500】[NOI2005]维修数列 Splay

【BZOJ1500】[NOI2005]维修数列 Description Input 输入的第1 行包含两个数N 和M(M ≤20 000)&#xff0c;N 表示初始时数列中数的个数&#xff0c;M表示要进行的操作数目。第2行包含N个数字&#xff0c;描述初始时的数列。以下M行&#xff0c;每行一条命令&#xff0c;格式参见…

bzoj2588: Spoj 10628. Count on a tree(树上第k大)(主席树)

每个节点继承父节点的树&#xff0c;则答案为query(root[x]root[y]-root[lca(x,y)]-root[fa[lca(x,y)]]) #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> using namespace std; const int maxn1…

图文详解YUV420数据格式

YUV格式有两大类&#xff1a;planar和packed。 对于planar的YUV格式&#xff0c;先连续存储所有像素点的Y&#xff0c;紧接着存储所有像素点的U&#xff0c;随后是所有像素点的V。 对于packed的YUV格式&#xff0c;每个像素点的Y,U,V是连续交*存储的。 YUV&#xff0c;分为三个…

USB通信接口介绍

1. 概述 Usb Universal Serial Bus全称通用串行总线&#xff0c;是一种支持热插拔的高速串行传输总线&#xff0c;使用差分信号来传输数据。 USB设备可以直接和host通信&#xff0c;或者通过hub和host通信。一个USB系统中仅有一个USB主机&#xff0c;设备包括功能设备和hub&…

HDCVI——一种创新性的高清视频传输方案

什么是HDCVI 2012年11月&#xff0c;大华技术股份有限公司发布了具有自主知识产权的同轴高清传输接口技术HDCVI。HDCVI技术是一种基于已有SYV75-3或SYV75-5同轴电缆的高清视频传输方法&#xff0c;能够在低成本和较低质量的同轴电缆上实现超长距离高清视频信号的可靠传输。相比…

智能机器人品牌简介

随着科技的发展&#xff0c;硬件的计算速度和大数据支撑&#xff0c;越来越多的智能化设备和产品出现在我们的面前&#xff0c;为我们的生活带来更多便利。其中包括智能机器人&#xff0c;这种产品是有自己的“大脑”&#xff0c;可以接收人为指令&#xff0c;为人服务&#xf…

诞生之日 随笔

今天我诞生了&#xff0c;祝自己诞生日happy&#xff0c;happy&#xff0c;happy&#xff01; 转载于:https://www.cnblogs.com/xiaohuihui-/p/7594406.html

智能音箱 之 麦克风参数介绍

1. 定义 麦克风&#xff0c;学名为传声器&#xff0c;是将声音信号转换为电信号的能量转换器件&#xff1b;声—电转换。 与扬声器正好相反&#xff08;电—声转换&#xff09;&#xff0c;构成电声设备的两个终端&#xff0c;俗称咪头&#xff0c;麦克等。 是电声系统的入口&a…

利用django框架,手把手教你搭建数据可视化系统(一)

如何使用django去构建数据可视化的 web,可视化的结果可以呈现在web上。 使用django的MTV模型搭建网站 基础铺垫—MTV模型 Created with Raphal 2.1.0Request服务器&#xff08;Djangoweb&#xff09;Response首先&#xff0c;要搞清楚我们去访问服务器&#xff0c;服务器返回信…

智能音箱 之 扬声器喇叭介绍

在全双工语音交互的系统中&#xff0c;功放的质量是非常重要的&#xff0c;因为AEC回声消除对信号失真 是非常敏感的。音频通路的整体谐波失真需要控制在5%以内。 对于整个系统的谐波失真来说&#xff0c;扬声器是最关键的因素&#xff0c;其次是功放&#xff0c;麦克风的很小…

UML学习——类图(三)

1.类图 UML类图是用来描述类、接口、协作及它们之间的关系的图。用来显示系统中各个类的静态结构。 2.类图的组成元素 类图由以下六种元素组成&#xff1a;类&#xff0c;接口&#xff0c;泛化关系&#xff0c;关联关系&#xff0c;依赖关系&#xff0c;实现关系。 3.类图的绘制…

传锤子科技解散成都分公司 才搬迁一年罗永浩就顶不住了

雷帝网 乐天 10月16日报道今日有网友爆料&#xff0c;锤子科技解散成都分公司。有网友指出&#xff0c;爆料的人是锤子科技早期员工王前闯。网友爆料锤子成都研发中心解散网友爆料锤子成都研发中心解散2016年&#xff0c;锤子科技亏损4亿元&#xff0c;一直徘徊在破产的边缘&am…

Maven and Nexus2

2019独角兽企业重金招聘Python工程师标准>>> Maven and Nexus2 Maven是什么&#xff1f; 构建工具&#xff1a; 通过简单的命令&#xff0c;能够完成清理、编译、测试、打包、部署等一系列过程。同时&#xff0c;不得不提的是&#xff0c;Maven是跨平台的&#xff0…

Linux kernel的中断子系统之(九):tasklet

返回目录&#xff1a;《ARM-Linux中断系统》。 总结&#xff1a; 二介绍了tasklet存在的意义。 三介绍了通过tasklet_struct来抽想一个tasklet&#xff0c;每个CPU维护一个tasklet链表tasklet_vec/tasklet_hi_vec&#xff0c;然后介绍了如何定一个一个tasklet(静态/动态)&#…

智能音箱 之 功放介绍

基本分类 功率放大器分甲类功放&#xff08;A 类&#xff09;&#xff0c;乙类&#xff08;B 类&#xff09;&#xff0c;甲乙类&#xff08;AB 类&#xff09;和丁类&#xff08;D 类&#xff09;&#xff1b; A 类 指在信号的整个周期内&#xff0c;放大器的任何功率输出…