面向对象---继承/封装/多肽
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 等等 这就是互称为鸭子类型。
面向对象---继承/封装/多肽相关推荐
- python面向对象编程 -- 封装、继承
面向对象编程 -- 封装.继承 面向对象编程三要素:封装.继承和多态.本文主要看和封装.继承相关的概念:在python中多态的概念比较模糊,本文不做讨论. 1 封装 封装:将数据和操作组装到一起,对外 ...
- python面向对象编程(封装与继承)
一. 面向过程编程语言 "面向过程"(Procedure Oriented)是一种以过程为中心的编程思想.分析出解决问题所需要的步 骤,然后用函数把这些步骤一步一步实现,使用的时候 ...
- 面向对象之三大特性:继承,封装,多态
python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分 ...
- java程序员从笨鸟到菜鸟之_Java程序员从笨鸟到菜鸟之(二)面向对象之封装,继承,多态(上)...
Java是一种面向对象的语言,这是大家都知道的,他与那些像c语言等面向过程语言不同的是它本身所具有的面向对象的特性--封装,继承,多态,这也就是传说中的面向对象三大特性 一:从类和对象开始说起: Oo ...
- 如何理解面向对象的封装、继承、多态
如何理解面向对象的封装.继承.多态 面向对象可以说是一种对现实是事物的抽象,将一类事物抽象成一个类,类里面包含了这类事物具有的公共部分,以及我们对这些部分的操作,也就是对应的数据和过程. 面向对象思想 ...
- java面向对象(封装、重载、构造、继承)
在上节课中主要学习了"面向对象"的封装.方法的重载. 1.类的继承:是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类或者基类,子类会自动拥有父类 ...
- W6_面向对象_封装_继承_多继承_多态
W6_面向对象_封装_继承_多继承_多态 80.81.82.83.第02章节-Python3.5-面向对象介绍 84.第05章节-Python3.5-实例变量与类变量 85.第06章节-Python3 ...
- Python中的面向对象(类的实例化,面向对象的封装、继承与多态)
文章目录 1.面向对象的定义 1.1 定义类.属性和方法 1.2 如何将类转化为对象(实例化) 1.3 构造方法 2.面向对象的封装 2.1 封装的定义 2.2 封装的练习 1.体重与跑步 2.栈的功 ...
- python面向对象(1) —— 封装
面向对象由封装.继承和多态组成 封装:属性和方法写到类里 继承:子类继承父类方法与属性 多态:子类重写父类后再实例化为不同对象产生不同结果 类与对象 class Gun():def __init__( ...
最新文章
- Java一个线程能否结束另一个永不停止的线程
- hg 全局密码配置。
- Java黑皮书课后题第5章:*5.30(金融应用:复利值)假设你每月在储蓄账户上多存100美元,年利率为5%,那么每月利率是0.05 / 12 = 0.00417。编写程序提示用户输入数据显示定月钱数
- JDK 15 JAVA 15的新特性展望
- 摆脱困境:从计划作业中调用安全方法
- selenium firefox驱动_Python3+selenium配置常见报错解决方案
- 吃鱼可以不挑刺了?华中农业大学发现鳊鱼肌间刺表达基因,可培育“无刺鱼”...
- 95-34-030-Context-DefaultChannelHandlerContext
- 【Codeforces	1426	D】Non-zero Segments,贪心,前缀和,数组子段统计
- Python写数据结构:二叉树的创建和遍历
- 联通计算机用户名和密码,终极:联通路由器的默认登录密码是什么?
- zynq-7000系列基于zynq-zed的vivado初步设计之linux下控制PL扩展的UART
- win7配置magic mouse和keyboard
- Unity简单实现老虎机抽奖效果
- Android之基于小米天气的天气源库
- Linux SPI驱动框架(2)——控制器驱动层
- 第五章 如何使用java中的线程打印偶数和奇数
- Go-Micro微服务框架使用
- DW1000 UWB用于pixhawk室内定位
- 魔兽怀旧卓越服务器微信,魔兽怀旧服玩家吐槽:没有了工作室后,永久60级服务器一地鸡毛...
热门文章
- pycharm 新建项目时要勾选inherit global site-packages!pycharm 新建项目时要勾选inherit global site-packages
- 怎么愉快的复制网页上不能复制文字的方法
- 向大家介绍一位牛逼的IT老师 => 廖神
- GME语音服务基于浏览器解决方案
- Java Calendar 获得某一天的零时
- 四 、Redis 集群的搭建
- 跨境电商app开发搭建多语言商城后的运营技巧,一件了解电子商城及运营
- 《逆向工程核心原理》学习笔记 破解abex' crackme #1
- 首尔半导体在美国获得对飞利浦电视机永久禁售的专利判决
- 利用opencv创建圆形头像图标(背景透明)