Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式
一、组合
'''
1、什么是组合
组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象 2、为何用组合
组合也是用来解决类与类直接代码冗余问题的 3、如何用组合 '''
# 继承减少代码冗余,但是将类与类进行了强耦合,python不崇尚,所以能不用继承就尽量不用继承
class OldboyPeople:
school = 'oldboy' def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex class OldboyStudent(OldboyPeople):
def __init__(self,name,age,sex,stu_id):
OldboyPeople.__init__(self,name,age,sex)
self.stu_id=stu_id def choose_course(self):
print('%s is choosing course' %self.name) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level):
OldboyPeople.__init__(self,name,age,sex) #重用父类中的属性(功能)(减少代码冗余)------普通的函数传参,该传几个参数传几个参数
self.level=level def score(self,stu,num): #老师有修改学生成绩的功能,所以将学生对象和修改的成绩传入
stu.score=num
print('老师[%s]为学生[%s]打分[%s]' %(self.name,stu.name,num)) stu1=OldboyStudent('猪哥',19,'male',1)
tea1=OldboyTeacher('egon',18,'male',10) stu1.choose_course() #学生对象选择课程------猪哥 is choosing course
tea1.score(stu1,100) #对象的绑定方法--------老师[egon]为学生[猪哥]打分[100]
print(stu1.__dict__) #查看学生的字典属性----{'name': '猪哥', 'age': 19, 'sex': 'male', 'stu_id': 1, 'score': 100} # #定制课程类
class Course: #将学生和老师对象都有课程属性,所以将他们都有的属性抽出来,重新定义了一个课程类
def __init__(self,name,period,price): #调用类时自动触发
self.name=name
self.period=period
self.price=price
# 查看课程信息
def tell_info(self):
msg="""
课程名:%s
课程周期:%s
课程价钱:%s
""" %(self.name,self.period,self.price)
print(msg)
#定制人类--------老师和学生类都是人类
class OldboyPeople:
school = 'oldboy'
# 定制人类独有的数据属性
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex class OldboyStudent(OldboyPeople):
def __init__(self,name,age,sex,stu_id):
OldboyPeople.__init__(self,name,age,sex) #类直接点类体代码的函数属性,在子类中重用父类功能,就是一个普通的函数
self.stu_id=stu_id #子类派生出自己独有的数据属性 def choose_course(self): #子类派生出自己独有的数据属性
print('%s is choosing course' %self.name) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level):
OldboyPeople.__init__(self,name,age,sex) #子类重用父类中的方法
self.level=level #子类中派生出自己独有的属性 def score(self,stu,num): #子类派生出自己独有的函数属性
stu.score=num
print('老师[%s]为学生[%s]打分[%s]' %(self.name,stu.name,num)) # 创造课程----------------------------------对象
python=Course('python全栈开发','5mons',3000) #调用课程对象,产生课程对象,并自动触发__init__函数的执行
linux=Course('linux运维','5mons',800)
# python.tell_info() #课程对象直接绑定课程类下的方法,并将课程对象当做第一个对象自动传入
# linux.tell_info() # 创造学生与老师-----------------------------对象
stu1=OldboyStudent('猪哥',19,'male',1)
tea1=OldboyTeacher('egon',18,'male',10) # 重点
# 将学生、老师与课程对象关联/组合-------------将对象之间进行关联
# --------------------------关键-----------------------------------------------
stu1.course=python #---------------将学生对象stu1与课程对象python关联
tea1.course=linux #---------------将老师对象stu1与课程对象linux关联
# --------------------------关键-----------------------------------------------
'''组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象'''
# 即学生类产生的学生对象具备课程的属性,该课程的属性值是指向课程类中的课程对象的 stu1.course.tell_info() #--------------等价于python.tell_info(),会打印出学生的课程信息
tea1.course.tell_info() #--------------等价于linux.tell_info(),会打印出老师的课程信息
二、菱形继承问题
#coding:utf-8
'''
1、菱形继承
当一个子继承多个父类时,多个父类最终继承了同一个类,称之为菱形继承 2、菱形继承的问题:
python2区分经典类与新式类,如果子的继承是一个菱形继承,那么经典类与形式的区别为?
经典类下查找属性:深度优先查找-----------------一条道走到黑
新式类下查找属性:广度优先查找------------------最后才去找菱形的端点
''' class G(object):
# def test(self):
# print('from G')
pass class E(G):
# def test(self):
# print('from E')
pass class B(E):
# def test(self):
# print('from B')
pass class F(G):
# def test(self):
# print('from F')
pass class C(F):
# def test(self):
# print('from C')
pass class D(G):
# def test(self):
# print('from D')
pass class A(B,C,D):
def test(self):
print('from A')
# pass obj=A()
#C3算法只试用新式类,经典类不适用
print(A.mro()) #mro是一种C3算法,[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
obj.test() #A->B->E-C-F-D->G-object-------对象属性的查找会严格按照mro列表的顺序进行查找
三、在子类派生的新方法中重用父类功能的两种方式
# 在子派生的新方法中重用父类功能的两种方式
# 方式一:与继承无关
#指名道姓法,直接用:类名.函数名
class OldboyPeople:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex class OldboyStudent(OldboyPeople):
def __init__(self,name,age,sex,stu_id):
OldboyPeople.__init__(self,name,age,sex) #-------(减少代码冗余)指名道姓法,直接用:类名.函数名,按照函数传参的规则进行传参即可
self.stu_id=stu_id #子类派生出自己独有的数据属性 def choose_course(self): #子类派生出自己的函数属性
print('%s is choosing course' %self.name) # 方式二:严格以mro列表继承属性查找关系
# super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
# super().__init__(不用为self传值)------------可以理解为super()是一个特殊的对象,所以对象绑定方法有一个自动传值的效果
# 注意:
# super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以简写为super()
class OldboyPeople:
school = 'oldboy' def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex class OldboyStudent(OldboyPeople):
# 定制学生类的数据属性,在定制数据属性的过程中,重用了父类中的数据属性
def __init__(self,name,age,sex,stu_id):
# OldboyPeople.__init__(self,name,age,sex) #------父类功能重用方法一
super(OldboyStudent,self).__init__(name,age,sex) #------父类功能重用方法二
self.stu_id=stu_id
#定制学生类的函数属性
def choose_course(self):
print('%s is choosing course' %self.name) stu1=OldboyStudent('猪哥',19,'male',1)
print(stu1.__dict__) #-------查看学生对象的字典属性,{'name': '猪哥', 'age': 19, 'sex': 'male', 'stu_id': 1}
print(OldboyStudent.mro()) #------查看学生类的继承关系,[<class '__main__.OldboyStudent'>, <class '__main__.OldboyPeople'>, <class 'object'>] # 继承顺序查找再应用:
class A:
def f1(self):
print('A.f1')
class B:
def f2(self):
super().f1() #B类和A类没有继承关系,但是会按照mro列表,从该类的下一个类继续进行查找,即此时会到A中进行查找
print('B.f2') class C(B,A):
pass obj=C()
print(C.mro()) #C-》B->A->object,查看C类的继承关系,[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
obj.f2() #对象属性的查找会严格按照mro列表的顺序进行查找,自己的对象没有到自己的类中找,自己的类中没有,到父类中找,此时父类查找的先后顺序就是按照mro列表来的 # 打印结果:
'''
A.f1
B.f2
'''
四、多态与多态性
'''
1 什么是多态
多态指的是同一种事物的多种形态
水-》冰、水蒸气、液态水
动物-》人、狗、猪 2 为和要用多态
多态性:
继承同一个类的多个子类中有相同的方法名
那么子类产生的对象就可以不用考虑具体的类型而直接调用功能 3 如何用
'''
import abc
class Animal(metaclass=abc.ABCMeta): #定义一个抽象类,规范一个类的类(统一成一套标准)
@abc.abstractmethod #装饰器装饰后,意味着但凡继承类该类的方法,函数属性的属性名都必须与父类的函数属性名一致,否则就会报错
def speak(self):
pass
@abc.abstractmethod 子类此时就必须与父类拥有相同的方法名,否则实例化就会报错
def eat(self):
pass # Animal() #强调:父类是用来制定标准的,不能被实例化-------此时实例化就会报错,这并不是python崇尚的,python更多的是一种约定俗成的,而不是硬性的限制
class People(Animal):
def speak(self):
print('say hello') def eat(self):
pass class Dog(Animal):
def speak(self):
print('汪汪汪') def eat(self):
pass
class Pig(Animal):
def speak(self):
print('哼哼哼') def eat(self):
pass peo1=People()
dog1=Dog()
pig1=Pig()
#
#继承同一个动物类的多个子类(人、狗、猪类)中有相同的方法名(speak\eat),那么子类产生的对象就可以不用考虑具体的类型而直接调用功能
peo1.speak() #不用考虑具体的对象类型,而直接调用speak的功能
dog1.speak()
pig1.speak() # -----------------------不用考虑是什么动物来调用speak的函数属性,所以将其封装成一个功能-----------------------------------
def my_speak(animal):
animal.speak()
my_speak(peo1)
my_speak(dog1)
my_speak(pig1)
# -----------------------不用考虑是什么动物来调用speak的函数属性,所以将其封装成一个功能----------------------------------- # 不同的数据类型,他们都有统计长度的这个方法,所以我们想到的是将他们制定成一套方法,便于对不同的数据类型进行统计
l=[1,2,3]
s='helllo'
t=(1,2,3) print(l.__len__()) #用同一种形式去调用的好处就是将其功能封装成一个函数时,只需要传入对象就可以了
print(s.__len__()) #如果用不同的方法名去统计不同数据类型的长度,这样封装成函数时就需要制定不同的函数去封装
print(t.__len__()) # def len(obj):
# return obj.__len__() print(len(l)) # l.__len__()
print(len(s)) #s.__len__()
print(len(t)) # python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子
class Disk:
def read(self):
print('disk read') def write(self):
print('disk wirte') class Process:
def read(self):
print('process read') def write(self):
print('process wirte') class File:
def read(self):
print('file read') def write(self):
print('file wirte') obj1=Disk()
obj2=Process()
obj3=File() obj1.read()
obj1.write()
Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式的更多相关文章
- [面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序、菱形问题、继承原理、Mixins机制),组合]
[面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序.菱形问题.继承原理.Mixins机制),组合] 继承应用 类与类之间的继承指的是什么'是'什么的关系(比如人类,猪类 ...
- python之子类调用父类的两种方式
第一种方式 直接在子类中调用父类名: Vehicle.__init__(self,name,speed,load,power)#调用父类的实例 Vehicle.run(self) #调用父类的方法 # ...
- javascript消除字符串两边空格的两种方式,面向对象和函数式编程。python oop在调用时候的优点
主要是javascript中消除字符串空格,比较两种方式的不同 //面向对象,消除字符串两边空格 String.prototype.trim = function() { return this.re ...
- python基础----继承与派生、组合、接口与归一化设计、抽象类、子类中调用父类方法
一.什么是继承 继承是一种创建新的类的方式,在pyth ...
- python基础之类的继承与派生、组合、接口与归一化设计、抽象类、子类中调用父类方法
一.什么是继承 继承是一种创建新的类的方式,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类. 派生:子类继承了父类的属性,然后衍生出自己新的属性,如果子类衍生出的新 ...
- 基础知识:编程语言介绍、Python介绍、Python解释器安装、运行Python解释器的两种方式、变量、数据类型基本使用
2018年3月19日 今日学习内容: 1.编程语言的介绍 2.Python介绍 3.安装Python解释器(多版本共存) 4.运行Python解释器程序两种方式.(交互式与命令行式)(♥♥♥♥♥) 5 ...
- 周一02.3运行python程序的两种方式
一.运行python程序的两种方式 方法一:交互式: 优点:输入一行代码立刻返回结果 缺点:无法永久保存代码 方法二: ...
- Python字符串的两种方式——百分号方式,format的方式
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 执行python解释器的两种方式
执行python解释器的两种方式 1.交互式 python是高级语言,是解释型语言,逐行翻译,写一句翻译一句 print ('hello world') 2.命令行式 python和python解释器 ...
随机推荐
- 封装CoreGraphics的API简化绘图操作
封装CoreGraphics的API简化绘图操作 效果 说明 1. 将CoreGraphics的API接口抽象为对象,让绘图变得简单易懂 2. 简化常用的绘制操作 3. 源码长期更新 源码 https ...
- SQL语言DDL DML DCL TCL四种语言
1.DDL(Data Definition Language)数据库定义语言:DDL使我们有能力创建或删 除表格.可以定义索引(键),规定表之间的链接,以及施加表间的 约束. • 常见DDL 语句: ...
- Linux 系统的/etc目录
/etc目录下的重要文件 /etc/sysconfig/network 指定服务器上的网络配置信息 /etc/rc.d/init.d/network 网络配置脚本信息 网络配置脚本,开机通过脚本文件来 ...
- for/while 循环全部执行完,, 中途不会停下!!中途不会停下!!中途不会停下!!! 中途不会停下!!!!!
对于这样一个在for 里面的, 他会从开始到最后走走一遍,然后再回到开始, 而不是在里面有两个操作,全部操作完第一个再往下走, 这个和我的学习方法似乎一样,真的要全局来一遍,再从新来一遍回顾问题 下面 ...
- Golang channel 用法简介
channel 是 golang 里相当有趣的一个功能,大部分时候 channel 都是和 goroutine 一起配合使用.本文主要介绍 channel 的一些有趣的用法. 通道(channel), ...
- ABAP知识点提纲
编号 课程名称 课程内容 预计课时 10.1.1~10.1.2 SAP系统与产品集 1. 了解SAP常见产品 ,了解SAP系统架构 1 10.1.3~10.1.4 导航界面与用户界面 1. 了解SAP ...
- luogu P3369 【模板】普通平衡树(splay)
嘟嘟嘟 突然觉得splay挺有意思,唯一不足的是这几天是一天一道,debug到崩溃. 做了几道平衡树基础题后,对这题有莫名的自信,还算愉快的敲完了代码后,发现样例都过不去,然后就陷入了无限的debug ...
- 20155314 2016-2017-2《Java程序设计》课程总结
20155314 2016-2017-2<Java程序设计>课程总结 每周作业链接汇总 预备作业1:刘子健的第一篇博客 预备作业2:刘子健的第二篇博客--有关CCCCC语言(・᷄ᵌ・᷅) ...
- mariadb密码问题
错误信息: Mysql:ERROR 1698 (28000): Access denied for user 'root'@'localhost' 解决办法: sudo cat /etc/mysql/ ...
- oracle数据库之操作总结
## 连接数据库: sqlplus test/test##@localhost:/ORCL ## 查询数据库所有的表: select table_name from user_tables; ## 查 ...