Py修行路 python基础 (十六)面向对象编程的 继承 多态与多态性 封装
一、继承顺序:
多继承情况下,有两种方式:深度优先和广度优先
1、py3/py2 新式类的继承:在查找属性时遵循:广度优先
继承顺序是多条分支,按照从左往右的顺序,进行一步一步查找,一个分支走完会走另一个分支(若多条分支汇总一个头,除最后一条分支能走到头,其他的都走到次之位置停止,进行下一条分支的查找),直到查找到头为止。
可以利用 类名.__mro__ 的方法查看类之间的继承关系(经典类没有这种方法)
class B(object):
def func(self):
print('-----> B')
pass
class C(object):
def func(self):
print('-----> C')
pass
class D(B,C):
def func(self):
print('-----> D')
pass
class E(B,C):
def func(self):
print('-----> E')
pass
class F(D,E):
def func(self):
print('-----> F')
pass
# f=F()
# f.func()
print(F.__mro__) #执行结果:
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
2、py2 经典类的继承:在查找属性时遵循:深度优先
一个子类继承多个父类,可以看作是多个分支,依然是遵循从左到右的顺序,只是第一条分支从尾走到头,找不到就会再走别的分支,只是最开始的父类不会再找。
3、继承原理
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
合并所有父类的MRO列表遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
子类继承了父类的方法,然后想进行修改,注意了是基于原有的基础上修改,那么就需要在子类中调用父类的方法
方法一:父类名.父类方法()
方法二:super()
两种方式,虽然都能调用,但是方法一存在极大的局限性,需要明确父类名,假如父类不存在,直接结果就会导致子类调用执行时报错,而super()是按照新式类的继承顺序,利用 super().函数名(参数) 的方式,继承父类方法。
使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次。
注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表
super在python2中的用法:
1:super(自己的类,self).父类的函数名字
2:super只能用于新式类
#coding:utf-8
#super在python2中的用法:
# 1:super(自己的类,self).父类的函数名字
# 2:super只能用于新式类
class People(object):
def __init__(self,name,sex,age):
self.name=name
self.age=age
self.sex=sex
def walk(self):
print('%s is walking' %self.name)
class Chinese(People):
country='China'
def __init__(self,name,sex,age,language='Chinese'):
# self.name=name
# self.sex=sex
# self.age=age
# People.__init__(self,name,sex,age)
super(Chinese,self).__init__(name,sex,age)
self.language=language
c=Chinese('egon','male',18)
print c.name,c.age,c.sex,c.language #执行结果:
egon 18 male Chinese
#在python3中
class People:
def __init__(self,name,sex,age):
self.name=name
self.age=age
self.sex=sex
def walk(self):
print('%s is walking' %self.name)
class Chinese(People):
country='China'
def __init__(self,name,sex,age,language='Chinese'):
super().__init__(name,sex,age)#super()函数.父类函数名(参数)
# 由于super()相当于是带入一个类而不在是函数,所以传值的时候,不再需要给self传值,实例化的时候自动带入。
self.language=language
def walk(self,x):
super().walk() #super()函数.父类函数名()
print('%s is chase %s'%(self.name,x))
c=Chinese('anyone','male',18)
print(c.name,c.age,c.sex,c.language)
c.walk('somebody') #执行结果:
anyone 18 male Chinese
anyone is walking
anyone is chase somebody
二、多态和多态性:
1、定义:
多态(是从定义角度出发):同一类事物的多种形态。(一个抽象类有多个子类,因而多态的概念依赖于继承)例如:动物的多种形态:人,狗,猪。
多态性(是从使用角度出发):同一种调用方式,不同的执行效果。具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。
多态性依赖于:1.继承;2.定义的接口
#定义统一的接口,可以传入不同类型的值,但是调用的逻辑都一样,但是执行的结果却不一样。
#多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度)
class Animal:
def run(self):
raise AttributeError('子类必须实现这个方法') class People(Animal):
def run(self):
print('人正在走') class Pig(Animal):
def run(self):
print('pig is walking') class Dog(Animal):
def run(self):
print('dog is running') peo1=People()
pig1=Pig()
d1=Dog()
#实例化调用方法得到的结果
# peo1.run()
# pig1.run()
# d1.run() #多态性:一种调用方式,不同的执行效果(多态性)
# 多态性依赖于:
# 1.继承
# 2.
##多态性:定义统一的接口,
def func(obj): #obj这个参数没有类型限制,可以传入不同类型的值
obj.run() #调用的逻辑都一样,执行的结果却不一样 func(peo1)
func(pig1)
func(d1) #执行结果:
人正在走
pig is walking
dog is running
多态性的实质:实质就是定义了一个函数接口,在这个函数中定义了所有类内通性的功能,只要传入参数(对象名)函数调用执行,就得到不同的结果。这就是所谓的一种调用方式,不同的执行结果。
2、 多态性的好处:
1、增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用
2、增加了程序的可扩展性
通过继承父类创建了一个新的子类,使用者无需更改自己的代码,还是用定义的接口函数去调用。
三、封装:
1、封装的本质就是隐藏,将一些复杂的执行过程隐藏起来,留下调用的接口(接口就是函数,称为接口函数;一组接口函数的集合体构成一个接口),我们通过这些接口进行交互,不管程序在内部怎么个应用流转方式,只为得到最后的结果。
2、数据封装主要原因是:保护隐私;方法封装主要原因是:隔离复杂度。
3、封装分为两个层面:
但无论哪种层面的封装,都要对外界提供好访问你内部隐藏内容的接口
第一层面的封装:其实就是创建类或是对象,通过类名.或对象名.的方式调用对应的方法,这本身就是一种封装。
注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口
第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
1、在python中用双下划线的方式实现隐藏属性(设置成私有的)。类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
class A:
__x =1 #_A__x
def __test(self): #_A__test
print('from A')
print(A.__dict__) #在方法空间中查看变形的属性
#print(A.__x) #用这种方法无法调用到变量,已变形
print(A._A__x) #若想强行访问,正确的调用方式
a = A() #实例化
print(a.__dict__)
print(a._A__x) #对象的调用 A._A__test(123) #强制访问,类的调用
a._A__test() #强制访问,对象的调用 #执行结果:
{'__module__': '__main__', '_A__x': 1, '_A__test': <function A.__test at 0x000000000292C9D8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
1
{}
1
from A
from A
2、注意:__名字,这种语法只在定义的时候才会有变形的效果,如果类或者对象已经产生了,就不会有变形效果。
变形的过程只在类的定义时发生一次;在定义后的赋值操作,就不会变形
#注意:__名字,这种语法只在定义的时候才会有变形的效果,如果类或者对象已经产生了,就不会有变形效果。
#变形的过程只在类的定义时发生一次;在定义后的赋值操作,就不会变形
#1、内部定义
class A:
def __init__(self):
self.__x =1 #_A__x 定义在产生的过程中,肯定会变形
def tell(self): #在类内部定义的变形变量(隐藏),需要定义一个接口函数来实现访问,外部去访问这个接口进行调用
print(self.__x) #在类内部可以直接用__名字调用,来访问到变形的属性
a = A()
print(a.__dict__) #在类的名称空间中查看,已变形
#print(a.__x) #属性已经变形,调用不到
a.tell() #执行结果:
{'_A__x': 1}
1 #2、外部定义
class B:
pass B.__x =1 #给类添加一个为__x的变量,而不是变形
print(B.__dict__) #在类的名称空间中查看,未变形
print(B.__x) #打印结果 b = B() #类实例化
b.__x =1 #为对象添加一个为__x的变量,而不是变形
print(b.__dict__) #查看对象的名称空间
print(b.__x) #打印结果 #执行结果:
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None, '__x': 1}
1
{'__x': 1}
1
3、在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
# 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
# 1、正常情况下:
class A:
def fa(self):
print('from A')
def test(self):
self.fa()
class B(A):
def fa(self):
print('from B')
b = B()
b.test() #b.test--->B--->A 得到b.fa() 然后在对象b中找--->类B找--->父类A找 # 执行结果:
from B # 注意:时刻谨记:在定义阶段就会变形
# 2、把fa定义成私有的,即__fa
class A:
def __fa(self): #_A__fa
print('from A')
def test(self): #在定义阶段就会变形
self.__fa() #self._A__fa
class B(A):
def __fa(self): #_B__fa
print('from B')
b = B() #实例化
b.test() #自己的对象和类名称空间没有,在父类的名称空间找到,函数已经变形。 #执行结果:
from A
Py修行路 python基础 (十六)面向对象编程的 继承 多态与多态性 封装的更多相关文章
- Py修行路 python基础(六)前期基础整理
计算机中,有且仅有CPU具有执行权限,能够执行指令的只有CPU! 人在应用程序上输入的文字或文本,叫做明文! 在屏幕上输入或是输出的是字符,计算机保存的是 有字符编码的 二进制数. 变量赋值规则:例如 ...
- Py修行路 python基础 (十五)面向对象编程 继承 组合 接口和抽象类
一.前提回忆: 1.类是用来描述某一类的事物,类的对象就是这一类事物中的一个个体.是事物就要有属性,属性分为 1:数据属性:就是变量 2:函数属性:就是函数,在面向对象里通常称为方法 注意:类和对象均 ...
- Py修行路 python基础 (十四)递归 及 面向对象初识及编程思想
一.递归 1.定义: 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. (1)递归就是在过程或函数里调用自身: (2)在使用递归策略时,必须有一个明确的递归结束条件 ...
- Py修行路 python基础 (十九)面向对象进阶(下)
item系列 __slots__方法 __next__ 和 __iter__实现迭代器 析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的格式. 例如:对象名['key'] ...
- Py修行路 python基础 (二十五)线程与进程
操作系统是用户和硬件沟通的桥梁 操作系统,位于底层硬件与应用软件之间的一层 工作方式:向下管理硬件,向上提供接口 操作系统进行切换操作: 把CPU的使用权切换给不同的进程. 1.出现IO操作 2.固定 ...
- Py修行路 python基础 (十八) 反射 内置attr 包装
一.isinstance 和 issubclass1.isinstance(obj,cls)检查是否obj是否是类 cls 的对象.2.issubclass(sub, super)检查sub类是否是 ...
- Py修行路 python基础 (二十)模块 time模块,random模块,hashlib模块,OS及sys模块
一.前提介绍: 可以开辟作用域的只有类,函数,和模块 for循环 if,else: 不能开辟自己的作用域 避免程序复用和重复调用,将这些写到一个.py文件中,做成一个模块,进行调 ...
- Py修行路 python基础 (十二) 协程函数应用 列表生成式 生成器表达式
一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._next_() 取下一个值 优点: 1.提供了 ...
- Py修行路 python基础 (二十四)socket编程
socket编程 一.客户端/服务端架构 客户端/服务端架构 即C/S架构,包括:1.硬件C/S架构,2.软件C/S架构. 互联网中处处都是C/S架构,学习socket 就是为了完成C/S架构的开发. ...
随机推荐
- 十 web爬虫讲解2—Scrapy框架爬虫—Scrapy安装—Scrapy指令
Scrapy框架安装 1.首先,终端执行命令升级pip: python -m pip install --upgrade pip2.安装,wheel(建议网络安装) pip install wheel ...
- 使用vue遇到坑
1.请求ajax方式一定要在Vue methods或creads里去请求. 方便做下拉刷新数据 . 2.多看看vue源码. 3.多写tab常项,h5下拉滚动,pc分页效果,回到顶部,提高熟悉vue需求 ...
- js区分字符串和数字,有时候需要将字符串转换成数字
js区分字符串和数字,有时候需要将字符串转换成数字 :parseInt
- NLTK下载语言素材中碰到的certificate verify failed (_ssl.c:749)
NLTK是什么? NLTK是一个开源的项目,包含:Python模块,数据集和教程,用于NLP的研究和开发. NLTK由Steven Bird和Edward Loper在宾夕法尼亚大学计算机和信息科学系 ...
- 9.链表中倒数第k个结点[FindReverseKthLinkedListNode]
[题目] 输入一个单向链表,输出该链表中倒数第k个结点.链表的倒数第0个结点为链表的尾指针.链表结点定义如下: C++ Code 12345 struct ListNode { int ...
- libwebsockets libwebsockets-webserver.c hacking
/********************************************************************************** * libwebsockets ...
- HDU - 6268: Master of Subgraph (分治+bitset优化背包)
题意:T组样例,给次给出一个N节点的点权树,以及M,问连通块的点权和sum的情况,输出sum=1到M,用0或者1表示. 思路:背包,N^2,由于是无向的连通块,所以可以用分治优化到NlgN. 然后背包 ...
- 在Git远程管理项目
新建repository 本地目录下,在命令行里新建一个代码仓库(repository) 里面只有一个README.md 命令如下: touch README.md git init 初 ...
- Mac 及 Xcode快捷键
mac快捷键: 窗口最大化:control+command+F 窗口最小化:command+M 关闭当前: command+W 退出程序: command+Q Safari往下翻页:空格 ...
- LG3380 3380 【模板】二逼平衡树(树套树)
题意 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在区间内的前驱(前驱定义为严格小于x ...