python-封装、继承、多态
封装
面向对象编程有三大特性:封装、继承、多态,其中最重要的一个特性就是封装。封装指的就是把数据与功能都整合到一起,针对封装到对象或者类中的属性,我们还可以严格控制对它们的访问,分两步实现:隐藏与开放接口,也就是后面出现的私有化属性和方法
# -*- coding: UTF-8 -*-
# @Date :2022/9/6 19:17
class School:
school_name = 'ShanXiPoliceCollege'
def __init__(self, nickname, addr):
self.addr = addr
self.nickname = nickname
self.classes = []
def related(self, class_obj):
# self.classes.append(class_name)
self.classes.append(class_obj)
def tell_class(self):
# 打印班级的名字
print(self.nickname.center(60, '='))
# 打印班级开设的课程信息
for class_obj in self.classes:
class_obj.tell_couse()
"""
# 创建学校
sch_obj1 = School('老男孩', '上海')
sch_obj2 = School('黑马程序员', '北京')
# 开设班级
sch_obj1.related('脱产14期')
sch_obj2.related('脱产15期')
#查看每个校区开设的班级
sch_obj1.tell_class()
sch_obj2.tell_class()
# sch_obj1.tell_classes()
"""
sch_obj1 = School('老男孩', '上海')
sch_obj2 = School('黑马程序员', '北京')
sch_obj3 = School('千锋教育', '北京')
class Class:
def __init__(self, name):
self.name = name
self.course = None
def related_course(self, course_obj):
self.course = course_obj
def tell_couse(self):
print('班级名:%s' % self.name, end=' ')
self.course.tell_info() # 打印课程的详细信息
# 创建班级
class_obj1 = Class('脱产14期')
class_obj2 = Class('脱产15期')
class_obj3 = Class('脱产16期')
# 2.为班级关联一个课程
# class_obj1.related_course('Python全栈开发')
# class_obj2.related_course('Linux运维')
# class_obj3.related_course('MySQL数据库')
# 3.查看班级开设的课程
# class_obj1.tell_couse()
# class_obj2.tell_couse()
# class_obj3.tell_couse()
# 4. 为学校开设班级
sch_obj1.related(class_obj1)
sch_obj2.related(class_obj2)
sch_obj3.related(class_obj2)
# sch_obj2.tell_class()
# sch_obj1.tell_class()
class Course:
def __init__(self, name, period, price):
self.name = name
self.period = period
self.price = price
def tell_info(self):
print('<%s-%s-%s>' % (self.name, self.period, self.price))
# 三:课程
# 1.创建课程
course_obj1 = Course('Python全栈开发', '6months', 20000)
course_obj2 = Course('Linux运维', '5months', 15000)
course_obj3 = Course('MySQL数据库', '2months', 8000)
# 2.查看课程详细信息
# course_obj1.tell_info()
# course_obj2.tell_info()
# 3.为班级关联课程对象
class_obj1.related_course(course_obj1)
class_obj2.related_course(course_obj2)
class_obj3.related_course(course_obj3)
# 4.
# class_obj1.tell_couse()
# class_obj2.tell_couse()
# class_obj3.tell_couse()
sch_obj1.tell_class()
sch_obj2.tell_class()
sch_obj3.tell_class()
继承
Python中展现面向对象的三大类型: 封装,继承,多
态
封装:值得是把内容封装到某个地方,便于后面的使用
他需要:
把内容封装到某个地方,从另外一个地方去到调用被封装的内容
对于封装来说,其实就是使用初始化构造方法将内容封装到对象中,然后通过对象直接或者self来获取被封装的内容继承:和现实生活当中的继承是一样的,也就是子可以继承父的内容【属性和行为】(爸爸有的儿子有, 相反, 儿子有的爸爸不一定有)。继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,新建的类可称为子类或派生类,父类又可称为基类或超类
所谓多态,定义时的类型和运行时的类型是不一样,此时就成为多态
单继承
class Animal:
def eat(self):
'''
吃
'''
print('吃')
def drink(self):
'''
喝
'''
print('喝')
class Dog(Animal):#继承Animal父类, 此时Dog就是子类
def wwj(self):
print('汪汪叫')
class Cat(Animal):
def mmj(self):
print('喵喵叫')
d1=Dog()
d1.eat()#继承了父类的行为
d1.wwj()
c1=Cat()
c1.drink()
c1.eat()
'''
对于面向对象的继承来说,其实就是将多个子类共有的方法提取到父类中,
子类仅仅需要继承父类而不必一一去实现
这样就可以极大提高效率,减少代码的重复编写,精简代码的层级结构 便于扩展
class 类名(父类):
pass
'''
通过类的内置属性__bases__
可以查看类继承的所有父类
print(Dog.__bases__)
"""结果如下"""
(<class '__main__.Animal'>,)
多继承
class shenxian:
def fly(self):
print('神仙会飞')
class Monkey:
def chitao(self):
print('猴子喜欢吃桃子')
class SunWuKong(shenxian,Monkey):
pass
swk=SunWuKong()
swk.fly()
swk.chitao()
#当多个父类当中存在相同方法时候,
class D:
def eat(self):
print('D.eat')
class C(D):
def eat(self):
print('C.eat')
class B(D):
pass
class A(B,C):
pass
a=A()
# b=B()
a.eat()
print(A.__mro__)#可以现实类的依次继承关系 查找执行顺序
#在执行eat方法时,顺序应该是
#首先到A里面去找,如果A中没有,则就继续去B类中去查找,如果B中没有,则去C中查找,
#如果C类中没有,则去D类中查找,如果还没有找到,就会报错
#A-B-C-D 也是继承的顺序
在Python2中有经典类与新式类之分,没有显式地继承object类的类,以及该类的子类,都是经典类,显式地继承object的类,以及该类的子类,都是新式类。而在Python3中,即使没有显式地继承object,也会默认继承该类,如下
print(shenxian.__bases__)
"""结果如下"""
(<class 'object'>,)
提示:object类提供了一些常用内置方法的实现,如用来在打印对象时返回字符串的内置方法__str__
属性查找
有了继承关系,对象在查找属性时,先从对象自己的__dict__
中找,如果没有则去子类中找,然后再去父类中找……
>>> class Foo:
... def f1(self):
... print('Foo.f1')
... def f2(self):
... print('Foo.f2')
... self.f1()
...
>>> class Bar(Foo):
... def f1(self):
... print('Foo.f1')
...
>>> b=Bar()
>>> b.f2()
Foo.f2
Foo.f1
"""
b.f2()会在父类Foo中找到f2,先打印Foo.f2,然后执行到self.f1(),即b.f1(),仍会按照:对象本身->类Bar->父类Foo的顺序依次找下去,在类Bar中找到f1,因而打印结果为Foo.f1
"""
父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的
>>> class Foo:
... def __f1(self): # 变形为_Foo__fa
... print('Foo.f1')
... def f2(self):
... print('Foo.f2')
... self.__f1() # 变形为self._Foo__fa,因而只会调用自己所在的类中的方法
...
>>> class Bar(Foo):
... def __f1(self): # 变形为_Bar__f1
... print('Foo.f1')
...
>>>
>>> b=Bar()
>>> b.f2() #在父类中找到f2方法,进而调用b._Foo__f1()方法,同样是在父类中找到该方法
Foo.f2
Foo.f1
继承实现原理
- 菱形问题,,或称钻石问题,有时候也被称为“死亡钻石”
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(B,C):
pass
obj = D()
obj.test() # 结果为:from B
- 继承原理
python到底是如何实现继承的呢? 对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表,如下
>>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
所以obj.test()的查找顺序是,先从对象obj本身的属性里找方法test,没有找到,则参照属性查找的发起者(即obj)所处类D的MRO列表来依次检索,首先在类D中未找到,然后再B中找到方法test
1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,
重写父类方法
- 所谓重写,就是子类中,有一个和父类相同名的方法,在子类中的方法会覆盖掉子类中同名的方法,
- 为什么要重写,父类的方法已经不满足子类的需要,那么子类就可以重写父类或者完善父类方法
当父类的方法实现不能满足子类的时候,可以对方法进行重写
重写父类的方法有两种
- 覆盖父类方法
class Father:
def smoke(self):
print('抽芙蓉王')
def drink(self):
print('喝二锅头')
class Son(Father):
#与父类的(抽烟)方法同名,这就是重写父类方法
def smoke(self):
print('抽中华')
#重写父类方法后,子类调用父类方法时,将调用的是子类的方法
son=Son()
son.smoke()
- 扩展父类方法
方法一:“指名道姓”地调用某一个类的函数
class Father:
def smoke(self):
print('抽芙蓉王')
def drink(self):
print('喝二锅头')
class Son(Father):
def drink(self):
##调用的是函数,因而需要传入self
Father.drink(self)
s = Son()
s.drink()
方法二:super()
"""
调用super()会得到一个特殊的对象,该对象专门用来引用父类的属性,且严格按照MRO规定的顺序向后查找
"""
class Father:
def smoke(self):
print('抽芙蓉王')
def drink(self):
print('喝二锅头')
class Son(Father):
def drink(self):
#调用的是绑定方法,自动传入self
super().drink()
s = Son()
s.drink()
"""结果如下"""
喝二锅头
class People:
school = '清华大学'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
class Teacher(People):
def __init__(self, name, sex, age, title): # 派生
#方法一
People.__init__(self, name, sex, age) # 调用的是函数,因而需要传入self
#方法二
super().__init__(name,age,sex) #调用的是绑定方法,自动传入self
self.title = title
def teach(self):
print('%s is teaching' % self.name)
obj = Teacher('lili', 'female', 28, '高级讲师') # 只会找自己类中的__init__,并不会自动调用父类的
print(obj.name)
这两种方式的区别是:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
#A没有继承B
class A:
def test(self):
super().test()
class B:
def test(self):
print('from B')
class C(A, B):
pass
print(C.mro()) # 在代码层面A并不是B的子类,但从MRO列表来看,属性查找时,就是按照顺序C->A->B->object,B就相当于A的“父类”
obj = C()
obj.test() # 属性查找的发起者是类C的对象obj,所以中途发生的属性查找都是参照C.mro()
"""结果如下"""
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
from B
obj.test()首先找到A下的test方法,执行super().test()会基于MRO列表(以C.mro()为准)当前所处的位置继续往后查找(),然后在B中找到了test方法并执行。
多态
- 所谓多态,定义时的类型和运行时的类型是不一样,此时就成为多态
#要想实现多态,必须有两个前提需要遵守:
'''
1.继承:多态必须放生在父类和子类之间
2.重写:子类重写父类的方法
'''
class Animal:
'''
基类[父类]
'''
def say(self):
print('我是一个动物'*10)
class Dark(Animal):
'''
子类【派生类】
'''
def say(self):
'''
重写父类方法
'''
print('我是一个鸭子'*10)
class Dog(Animal):
def say(self):
print('我是一只'*10)
# dark=Dark()
# dark.say()
#统一的去调用
def commonInvoke(obj):
obj.say()
list=[Dark(),Dog()]
for item in list:
'''
循环调用函数
'''
commonInvoke(item)
python-封装、继承、多态的更多相关文章
- Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态)
Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态) 1.面向对象的三大特性: (1)继承 继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可以 ...
- python面向对象(封装,继承,多态)
python面向对象(封装,继承,多态) 学习完本篇,你将会深入掌握 如何封装一个优雅的借口 python是如何实现继承 python的多态 封装 含义: 1.把对象的属性和方法结合成一个独立的单位, ...
- java面向对象(封装-继承-多态)
框架图 理解面向对象 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程强调的是功能行为 面向对象将功能封装进对象,强调具备了功能的对象. 面向对象是基于面向过程的. 面向对象的特点 ...
- 浅谈学习C++时用到的【封装继承多态】三个概念
封装继承多态这三个概念不是C++特有的,而是所有OOP具有的特性. 由于C++语言支持这三个特性,所以学习C++时不可避免的要理解这些概念. 而在大部分C++教材中这些概念是作为铺垫,接下来就花大部分 ...
- Java三大特性(封装,继承,多态)
Java中有三大特性,分别是封装继承多态,其理念十分抽象,并且是层层深入式的. 一.封装 概念:封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据 ...
- php面向对象 封装继承多态 接口、重载、抽象类、最终类总结
1.面向对象 封装继承多态 接口.重载.抽象类.最终类 面向对象 封装继承多态 首先,在解释面向对象之前先解释下什么是面向对象? [面向对象]1.什么是类? 具有相同属性(特征)和方法(行为)的一 ...
- Java基础——面向对象(封装——继承——多态 )
对象 对象: 是类的实例(实现世界中 真 实存在的一切事物 可以称为对象) 类: 类是对象的抽象描述 步骤: 1.定义一个类 (用于 描述人:) ( * 人:有特征和行为) 2.根据类 创建对象 -- ...
- OOP三大核心封装继承多态
OOP支柱 3 个核心:封装 继承 多态 封装就是将实现细节隐藏起来,也起到了数据保护的作用. 继承就是基于已有类来创建新类可以继承基类的核心功能. 在继承中 另外一种代码重用是:包含/委托,这种重用 ...
- Python设计模式 - 基础 - 封装 & 继承 & 多态
面向对象的核心是对象,世间万物都可以看作对象,任何一个对象都可以通过一系列属性和行为来描述,可以包含任意数量和类型的数据或操作.类是用来描述具有相同属性和方法的所有对象的集合.类通常是抽象化的概念,而 ...
- C语言设计模式-封装-继承-多态
快过年了,手头的工作慢慢也就少了,所以,研究技术的时间就多了很多时间,前些天在CSDN一博客看到有大牛在讨论C的设计模式,正好看到了,我也有兴趣转发,修改,研究一下. 记得读大学的时候,老师就告诉我们 ...
随机推荐
- AVL tree 高度上下界推导
1. 最大高度对应 Node 数量 \(N_{h}\) 的递归公式 设有一棵 AVL tree 的高度为 \(h\), 对于该树, 构成该树的最少 node 数量为 \(N_{h}\) . 有: 最坏 ...
- 创建Elasticsearch集群并为它们配置TLS安全通信
文章转载自:https://elasticstack.blog.csdn.net/article/details/105636302 文章开头讲述的是两台es主机构建一个集群,其中有关的配置可以借鉴 ...
- 5.Ceph 基础篇 - 认证
文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247485272&idx=1&sn=4b27c357 ...
- MinIO对接k8s使用
文档地址:https://github.com/minio/operator/blob/master/README.md https://docs.min.io/minio/k8s/deploymen ...
- RabbitMQ各个端口被占用的进程说明
官方地址:https://www.rabbitmq.com/networking.html#ports 端口 描述 4369 erlang 发现端口,被 epmd 占用,用于 RabbitMQ 节点和 ...
- MySQL 中 datetime 和 timestamp 的区别与选择
MySQL 中常用的两种时间储存类型分别是datetime和 timestamp.如何在它们之间选择是建表时必要的考虑.下面就谈谈他们的区别和怎么选择. 1 区别 1.1 占用空间 类型 占据字节 表 ...
- Beats: 使用 Filebeat 进行日志json结构化 - Python
文章转载自:https://elasticstack.blog.csdn.net/article/details/106688240
- 使用docker-compose部署Django项目
先从最基本的功能开始 在一切工作开始前,需要先编辑好三个必要的文件. 第一步,因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面,那么我们可以通过编辑 Dockerfile 文件来指定 ...
- PAT (Basic Level) Practice 1031 查验身份证 分数 15
一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8, ...
- Python实现改进后的Bi-RRT算法实例
Python实现改进后的Bi-RRT算法实例 1.背景说明 以下代码是参照上海交通大学海洋工程国家重点实验室<基于改进双向RRT的无人艇局部路径规划算法研究>的算法思想实现的. 2.算法流 ...