1. 继承

比较官方的说法就是:

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

1.1 案例

class Person:def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sex
class Cat:def __init__(self,name,sex,age):self.name = nameself.age = ageself.sex = sex
class 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 = sex
class Person(Aniaml):pass
class Cat(Aniaml):pass
class Dog(Aniaml):pass

1.2 继承的有点也是显而易见的:

  • 增加了类的耦合性(耦合性不宜多,宜精)。
  • 减少了重复代码。
  • 使得代码更加规范化,合理化。

1.3 继承的分类

1.3.1 就向上面的例子:

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

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

  • python3x版本中只有一种类。
  • python3中使用的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object。

1.3.3 在python2x版本中存在两种类.:

  • 一个叫经典类. 在python2.2之前. 一直使用的是经典类. 经典类在基类的根如果什么都不写.
  • 一个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。

1.3.4 经典与新式的查找顺序

  • 经典深度优先,一条路走到黑,没找到,折回上一级继续找
  • 新式广度优先,从左往右找

1.4 单继承

1.4.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):pass
class Cat(Aniaml):pass
class 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()

1.4.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):pass
class Dog(Aniaml):pass
p1 = Person('barry','男',18)
# 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
p1.eat()
# 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。

1.4.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):pass
class 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):pass
class Dog(Aniaml):pass
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)

1.5 新式类多继承

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

1.6 经典类的多继承

  • 虽然在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.

2. 封装

  • 把很多数据封装到一个对象中. 把固定功能的代码封装到一个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想.
  • 具体的情况具体分析. 比如. 你写了一个很牛B的函数. 那这个也可以被称为封装. 在面向对象思想中. 是把一些看似无关紧要的内容组合到一起统一进行存储和使用. 这就是封装.
  • 封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
  • 所以,在使用面向对象的封装特性时,需要:

将内容封装到某处,

从某处调用被封装的内容

2.1 第一步:将内容封装到某处

  • self 是一个形式参数,当执行 obj1 = Foo(‘wupeiqi’, 18 ) 时,self 等于 obj1
  • ​ 当执行 obj2 = Foo(‘alex’, 78 ) 时,self 等于 obj2
  • 所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。

2.2 第二步:从某处调用被封装的内容

2.2.1 调用被封装的内容时,有两种情况:

  • 通过对象直接调用
  • 通过self间接调用

2.2.2 通过对象直接调用被封装的内容

  • 上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名
class Foo:def __init__(self, name, age):self.name = nameself.age = age
obj1 = Foo('wupeiqi', 18)
print obj1.name    # 直接调用obj1对象的name属性
print obj1.age     # 直接调用obj1对象的age属性
obj2 = Foo('alex', 73)
print obj2.name    # 直接调用obj2对象的name属性
print obj2.age     # 直接调用obj2对象的age属性

2.2.3 通过self间接调用被封装的内容

  • 执行类中的方法时,需要通过self间接调用被封装的内容
class Foo:def __init__(self, name, age):self.name = nameself.age = agedef detail(self):print self.nameprint self.age
obj1 = Foo('wupeiqi', 18)
obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18
obj2 = Foo('alex', 73)
obj2.detail()  # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78

2.3 总结

  • 综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
  • 子类可以自动拥有父类中除了私有属性外的其他所有内容.
  • 说白了, 儿子可以随便用爹的东西. 但是朋友们, 一定要认清楚一个事情. 必须先有爹, 后有儿子. 顺序不能乱,
  • 在python中实现继承非常简单. 在声明类的时候, 在类名后面添加一个小括号,就可以完成继承关系.
  • 那么什么情况可以使用继承呢? 单纯的从代码层面上来看. 两个类具有相同的功能或者特征的时候. 可以采用继承的形式. 提取一个父类, 这个父类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码.
  • 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是一种y.
  • 这时, y是一种泛化的概念. x比y更加具体. 那这时x就是y的子类.
  • 比如. 猫是一种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的”动”这个属性. 再比如, 白骨精是一个妖怪. 妖怪天生就有一个比较不好的功能叫”吃人”, 白骨精一出生就知道如何”吃人”. 此时 白骨精继承妖精.

3 多态

  • 同一个对象, 多种形态. 这个在python中其实是很不容易说明白的. 因为我们一直在用. 只是没有具体的说.
  • 比如. 我们创建一个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = “alex”, 这时, a又变成了字符串类型. 这是我们都知道的.
  • 但是, 我要告诉你的是. 这个就是多态性. 同一个变量a可以是多种形态。
  • 多态,同一个对象,多种形态。python默认支持多态。
# 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。
def func(int a):print('a必须是数字')
# 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
def func(a):print('a是什么都可以')
# 再比如:
class F1:pass
class S1(F1):def show(self):print 'S1.show'
class S2(F1):def show(self):print 'S2.show'
# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象
def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""print obj.show()
s1_obj = S1()
Func(s1_obj)  # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show
s2_obj = S2()
Func(s2_obj)  # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
Python伪代码实现Java或C  # 的多态

3.2 鸭子类型

python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
对于代码上的解释其实很简答:
class A:def f1(self):print('in A f1')def f2(self):print('in A f2')
class B:def f1(self):print('in A f1')def f2(self):print('in A f2')
obj = A()
obj.f1()
obj.f2()
obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
# 这样的例子比比皆是:str  tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。

面向对象---继承/封装/多肽相关推荐

  1. python面向对象编程 -- 封装、继承

    面向对象编程 -- 封装.继承 面向对象编程三要素:封装.继承和多态.本文主要看和封装.继承相关的概念:在python中多态的概念比较模糊,本文不做讨论. 1 封装 封装:将数据和操作组装到一起,对外 ...

  2. python面向对象编程(封装与继承)

    一. 面向过程编程语言 "面向过程"(Procedure Oriented)是一种以过程为中心的编程思想.分析出解决问题所需要的步 骤,然后用函数把这些步骤一步一步实现,使用的时候 ...

  3. 面向对象之三大特性:继承,封装,多态

    python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分 ...

  4. java程序员从笨鸟到菜鸟之_Java程序员从笨鸟到菜鸟之(二)面向对象之封装,继承,多态(上)...

    Java是一种面向对象的语言,这是大家都知道的,他与那些像c语言等面向过程语言不同的是它本身所具有的面向对象的特性--封装,继承,多态,这也就是传说中的面向对象三大特性 一:从类和对象开始说起: Oo ...

  5. 如何理解面向对象的封装、继承、多态

    如何理解面向对象的封装.继承.多态 面向对象可以说是一种对现实是事物的抽象,将一类事物抽象成一个类,类里面包含了这类事物具有的公共部分,以及我们对这些部分的操作,也就是对应的数据和过程. 面向对象思想 ...

  6. java面向对象(封装、重载、构造、继承)

    在上节课中主要学习了"面向对象"的封装.方法的重载. 1.类的继承:是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类或者基类,子类会自动拥有父类 ...

  7. W6_面向对象_封装_继承_多继承_多态

    W6_面向对象_封装_继承_多继承_多态 80.81.82.83.第02章节-Python3.5-面向对象介绍 84.第05章节-Python3.5-实例变量与类变量 85.第06章节-Python3 ...

  8. Python中的面向对象(类的实例化,面向对象的封装、继承与多态)

    文章目录 1.面向对象的定义 1.1 定义类.属性和方法 1.2 如何将类转化为对象(实例化) 1.3 构造方法 2.面向对象的封装 2.1 封装的定义 2.2 封装的练习 1.体重与跑步 2.栈的功 ...

  9. python面向对象(1) —— 封装

    面向对象由封装.继承和多态组成 封装:属性和方法写到类里 继承:子类继承父类方法与属性 多态:子类重写父类后再实例化为不同对象产生不同结果 类与对象 class Gun():def __init__( ...

最新文章

  1. Java一个线程能否结束另一个永不停止的线程
  2. hg 全局密码配置。
  3. Java黑皮书课后题第5章:*5.30(金融应用:复利值)假设你每月在储蓄账户上多存100美元,年利率为5%,那么每月利率是0.05 / 12 = 0.00417。编写程序提示用户输入数据显示定月钱数
  4. JDK 15 JAVA 15的新特性展望
  5. 摆脱困境:从计划作业中调用安全方法
  6. selenium firefox驱动_Python3+selenium配置常见报错解决方案
  7. 吃鱼可以不挑刺了?华中农业大学发现鳊鱼肌间刺表达基因,可培育“无刺鱼”...
  8. 95-34-030-Context-DefaultChannelHandlerContext
  9. 【Codeforces 1426 D】Non-zero Segments,贪心,前缀和,数组子段统计
  10. Python写数据结构:二叉树的创建和遍历
  11. 联通计算机用户名和密码,终极:联通路由器的默认登录密码是什么?
  12. zynq-7000系列基于zynq-zed的vivado初步设计之linux下控制PL扩展的UART
  13. win7配置magic mouse和keyboard
  14. Unity简单实现老虎机抽奖效果
  15. Android之基于小米天气的天气源库
  16. Linux SPI驱动框架(2)——控制器驱动层
  17. 第五章 如何使用java中的线程打印偶数和奇数
  18. Go-Micro微服务框架使用
  19. DW1000 UWB用于pixhawk室内定位
  20. 魔兽怀旧卓越服务器微信,魔兽怀旧服玩家吐槽:没有了工作室后,永久60级服务器一地鸡毛...

热门文章

  1. pycharm 新建项目时要勾选inherit global site-packages!pycharm 新建项目时要勾选inherit global site-packages
  2. 怎么愉快的复制网页上不能复制文字的方法
  3. 向大家介绍一位牛逼的IT老师 => 廖神
  4. GME语音服务基于浏览器解决方案
  5. Java Calendar 获得某一天的零时
  6. 四 、Redis 集群的搭建
  7. 跨境电商app开发搭建多语言商城后的运营技巧,一件了解电子商城及运营
  8. 《逆向工程核心原理》学习笔记 破解abex' crackme #1
  9. 首尔半导体在美国获得对飞利浦电视机永久禁售的专利判决
  10. 利用opencv创建圆形头像图标(背景透明)