day15-面向对象基础(二)
今天整理类的组合以及类的三大特性
1.类的组合
2.类的继承
3.类的封装
4.类的多态
开始今日份整理
1.类的组合
类与类之间,并不是独立的,很多的时候在正常使用的时候都是类与类之间互相调用,所以就需要对类与类之间的关联或者是联系进行整理一下,就拿之前的英雄联盟的游戏人物之间的关系举例。
1.1类的组合
在定义lol中不同的英雄人物,那么正常游戏过程中,是需要使用武器等,这个时候就用到了组合,查看代码
class Game_role():
def __init__(self,name,ad,hp):
self.name = name
self.ad = ad
self.hp = hp
def attack(self,obj):
obj.hp -= self.ad
print('{}打了{}一次,{}丢失{}点血量,现在血量为{}'.format(self.name,obj.name,obj.name,self.ad,obj.hp))
def equip_weapon(self,obj):
self.weapon = obj class Weapon():
def __init__(self,name,ad):
self.name = name
self.ad = ad def attack_weapon(self,obj1,obj2):
obj2.hp -=(self.ad+obj1.ad)
print('{}用{}打了{}一下,{}还剩{}点血量'.format(obj1.name,self.name,obj2.name,obj2.name,obj2.hp)) r1 = Game_role('盖伦',,)
r2 = Game_role('剑姬',,)
w1 = Weapon('三相',)
r1.equip_weapon(w1)
r1.weapon.attack_weapon(r1,r2)
#结果
盖伦用三相打了剑姬一下,剑姬还剩105点血量
这个算最基本的类之间的组合,对于类的组合,其实就是给一个对象封装一个属性,而这个属性是另外一个对象,也是最low的了。不过类的组合也是有好处的
- 代码之间的关系更加合理
- 类与类之间的耦合性增强
一些小的测试题
,暴力摩托程序(完成下列需求):
.1创建三个游戏人物,分别是:
• 苍井井,女,,攻击力ad为20,血量200
• 东尼木木,男,,攻击力ad为30,血量150
• 波多多,女,,攻击力ad为50,血量80
.2创建三个游戏武器,分别是:
• 平底锅,ad为20
• 斧子,ad为50
• 双节棍,ad为65 1.3 创建三个游戏摩托车,分别是: • 小踏板,速度60迈
• 雅马哈,速度80迈
• 宝马,速度120迈。 完成下列需求(利用武器打人掉的血量为武器的ad + 人的ad):
()苍井井骑着小踏板开着60迈的车行驶在赛道上。
()东尼木木骑着宝马开着120迈的车行驶在赛道上。
()波多多骑着雅马哈开着80迈的车行驶在赛道上。
()苍井井赤手空拳打了波多多20滴血,波多多还剩xx血。
()东尼木木赤手空拳打了波多多30滴血,波多多还剩xx血。
()波多多利用平底锅打了苍井井一平底锅,苍井井还剩xx血。
()波多多利用斧子打了东尼木木一斧子,东尼木木还剩xx血。
()苍井井骑着宝马打了骑着小踏板的东尼木木一双节棍,东尼木木哭了,还剩xx血。(选做)
()波多多骑着小踏板打了骑着雅马哈的东尼木木一斧子,东尼木木哭了,还剩xx血。
1.2类的依赖
类的依赖:给一个类的方法传了一个参数,而这个参数是一个类的对象,这种依赖关系是关系中紧密型最低的,耦合性最低的,就像上面的lol中人自身的攻击手段,他调用的是对方的对象,这个时候盖伦中有剑姬,而剑姬没有盖伦,并不是像武器,武器已经完全变成盖伦的属性而存在,紧密结合。用大象关冰箱来做一个测试。
class Elephant():
def __init__(self,name):
self.name = name def open_door(self,obj):
print('1,2,3,开门')
obj.open_() def close_door(self,obj):
print('3,2,1,关门 ')
obj.close_() class Refrigerator():
def __init__(self,name):
self.name = name def open_(self):
print('门正在打开') def close_(self):
print('门正在关闭')
e1 = Elephant('神奇的大象')
r1 = Refrigerator('海尔')
e1.open_door(r1)
e1.close_door(r1)
和上面的相比,这次对象同样调用了另外的obj,可是只是使用了方法,并没有让obj成为自己的属性
1.3类的关联,聚合关系,组合关系
其实这个关系还是组合,还是举俩个例子吧,一个陪女友吃饭,一个是教师关联学校
陪女友吃饭
class Boy():
def __init__(self,name,girelfriend=None):
self.name = name
self.girlfrind = girelfriend def have_dinner(self):
if self.girlfrind == None:
print('单身狗,吃啥吃!')
else:
print('%s 与%s共进晚餐'%(self.name,self.girlfrind.name)) def get_girlfrind(self,obj):
self.girlfrind = obj def lose_girlfriend(self):
self.girlfrind = None class Girl():
def __init__(self,name):
self.name = name
b1 = Boy('屌丝')#无女友
g1 = Girl('美女')
b2 = Boy('小哥',g1)#有娃娃亲 b1.have_dinner()
b2.have_dinner()
教师关联学校
class School():
def __init__(self,city,address):
self.city = city
self.address = address
self.teacher_list = [] class Teacher():
def __init__(self,name,language):
self.name = name
self.language = language
self.school = None def binding(self,li):
for i,j in enumerate(li):
print(i,'学校所在地址为%s'%j.city)
choice = int(input('你所选择的学校的序号>>>').strip())
self.school = li[choice]#教师绑定了学校
li[choice].teacher_list.append(self)#学校绑定了教师
print('学校绑定教师成功') school1 =School('北京','昌平')
school2 =School('上海','张江') li = [school1,school2] test1 =Teacher('alex','python')
test1.binding(li) for i in school1.teacher_list:
print(i.name,i.language)
2.类的继承
就像人和狗都属于动物,人和狗都有年龄啊什么的共同方法,那么我们就可以写一个公共类,狗和人继承好了
class Animal:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('在吃东西') class People(Animal):
def __init__(self,name,age,sex,skin):
#方式一
Animal.__init__(self,name,age,sex)
#方式二
super().__init__(name,age,sex)
self.skin = skin
def eat(self):
print('人在吃东西')
#对于狗也是一样
2.1类的单继承
类的单继承就是字面意思,一个类只有一个父类用于继承,父类又称之为基类或者是超类,子类又称之为派生类
就像上面的例子,people类继承了animal类,people类可以使用父类的属性以及方法。
查看子类的继承情况为:print(类.__base__)
# 既要执行子类方法,又要执行父类方法
# 方法一: Aniaml.__init__(self,name,sex,age)
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__) # 方法二:super
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)
# def func(self):
# pass
# self = 3
# func(self) # p1 = Person('春哥','laddboy',18,'有思想')
# p1.eat()
对于单继承就是这样了。
2.2类的多继承
类的多继承可以这么理解,就是一个儿子有多个爹,然后类的继承就需要排序了。对于类的分类,主要有经典类与新式类俩种
- 经典类:python 2.x系列中,不继承基类object,对于类的查找属于一条道走到黑,深度优先
- 新式类:python 2.x系列中,继承基类object,python3.x系列中,默认都是新式类,查找按照c3算法
经典类的查询,如图,就是一条道走到黑
新式类的查询,采用c3算法
c3算法:# #mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
下面是推倒过程
# #mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
mro(K(H,I)) =[K]+merge(mro(H),mro(I),[H,I]) mro(H(E,F)) = [H] +merge(mro(E),mro(F),[E,F])
mro(E(B,C)) = [E] +merge([B,A],[C,A],[B,C])
mro(E(B,C)) = [E,B] +merge([A],[C,A],[C]) mro(E(B,C)) = [E,B,C,A] mro(F(C,D)) = [F] +merge([C,A],[D,A],[C,D])
mro(F(C,D)) = [F,C] +merge([A],[D,A],[D]) mro(F(C,D)) = [F,C,D,A] mro(H(E,F)) = [H] +merge([E,B,C,A],[F,C,D,A],[E,F])
mro(H(E,F)) = [H,E] +merge([B,C,A],[F,C,D,A],[F])
mro(H(E,F)) = [H,E,B] +merge([C,A],[F,C,D,A],[F])
mro(H(E,F)) = [H,E,B,F] +merge([C,A],[C,D,A])
mro(H(E,F)) = [H,E,B,F,C,] +merge([A],[D,A]) mro(H(E,F)) = [H,E,B,F,C,D,A] mro(I(F,G)) =[I] +merge(mro(F),mro(G),[F,G])
mro(F(C,D)) = [F] +merge(mro[C],mro[D],[C,D])
mro(F(C,D)) = [F] +merge([C,A],D,A,[C,D])
mro(F(C,D)) = [F,C] +merge([A],D,A,[D]) mro(F(C,D)) = [F,C,D,A] mro(G)=[D,A] mro(I(F,G)) =[I] +merge([F,C,D,A],[G,D,A],[F,G])
mro(I(F,G)) =[I,F] +merge([C,D,A],[G,D,A],[G])
mro(I(F,G)) =[I,F,C] +merge([D,A],[G,D,A],[G])
mro(I(F,G)) =[I,F,C,G] +merge([D,A],[D,A])
mro(I(F,G)) =[I,F,C,G,D,A] mro(K(H,I)) =[K]+merge([H,E,B,F,C,D,A],[I,F,C,G,D,A],[H,I])
mro(K(H,I)) =[K,H]+merge([E,B,F,C,D,A],[I,F,C,G,D,A],[I])
mro(K(H,I)) =[K,H,E,B,I]+merge([F,C,D,A],[F,C,G,D,A])
mro(K(H,I)) =[K,H,E,B,I,F,C]+merge([D,A],[G,D,A])
mro(K(H,I)) =[K,H,E,B,I,F,C,G,D,A]
#最后的执行顺序就是[K,H,E,B,I,F,C,G,D,A]
如果不用这种手算的推导式,其实可以直接调用方法查看
print(K.__mro__)
#结果和上面是一致的
super()也是按照上面的c3算法来调用的
根据上面做一些派生
子类可以添加自己新的属性或者在自己这里定义这些属性(不会影响父类),需要注意的是,一旦重新定义了与父类相同的名字的属性,会以自己为准。
在子类中,新建的重名函数类型,在编辑函数功能时,有可能调用父类的相同名字的函数功能时,应该用普通函数方法一样,因此即使是self也应该传值进去,例如类名.func(参数)
继承原理:
- 子类会先于父类检查
- 多个父类会根据他们在列表中的顺序被检查
- 如果对下一个类存在俩个合法选择,选择第一个父类
3.类的封装
在讲类的封装的前提需要说一下类方法的隐藏
3.1隐藏
类的结构中可以分静态属性以及动态属性,按照另外一个角度,可以划分为公有,私有属性
class Boss():
name = 'alex'
__secretary =['女一','男二','野模']#私有静态属性 def __init__(self,username,password):
self.username = username
self.__password = password#私有对象属性 def func(self):
print('老板在办公') def __func1(self):
print('老板在和秘书办公')#私有方法 def print(self):
print(self.__secretary)
self.__func1()
b1 = Boss('alex',123) print(b1.name)
#print(b1.__secretary)
b1.print()
我们会发现,按照以前的一样的调用方法,根本得不到这些私有属性以及私有方法,如果我们在类内定义一个函数专门用于调用这些私有方法,才能看到这些私有属性,单独的去调用这些私有属性只会报错没有这些方法,我们会发现只有类的内部才能调用,类的外部以及派生类根本无法调用属性。
不过并不是完全无法调用,当我们看类的__dict__方法时,我们会发现,python对类内部这些私有方法属性进行了包装
{'_Boss__secretary': ['女一', '男二', '野模'], '__doc__': None, '__init__': <function Boss.__init__ at 0x016246A8>, 'name': 'alex', '_Boss__func1': <function Boss.__func1 at 0x016D40C0>, 'print': <function Boss.print at 0x016D4078>, '__weakref__': <attribute '__weakref__' of 'Boss' objects>, '__dict__': <attribute '__dict__' of 'Boss' objects>, 'func': <function Boss.func at 0x016D4030>, '__module__': '__main__'}
我们采用_boss__password这样的形式还是可以调用的。不过一般不建议这么使用,变形后的注意问题
- 这种隐藏并不是真正意思上的隐藏
- 变形的过程发生在类的定义发生一次,定义后的操作,不会变形
- 在继承中,如果父类不想子类覆盖子类自己的方法,可以将方法定义为私有,子类就不会继承到这些方法
3.2封装的意义
封装的意义为
- 封装数据:明确区分类内外的,控制外部对隐藏属性的操作
- 封装方法:隔离复杂度,只需要提供接口给其他人使用即可
3.3propetry函数
propetry也叫做类的私有属性
class Market():
def __init__(self,name,prix,discount):
self.name = name
self.__prix = prix
self.__discount = discount @property#设定为私有方法
def price(self):
return self.__prix*self.__discount @price.setter#对私有方法的内容进行修改
def price(self,new_price):
self.__prix = new_price @price.deleter#对私有方法的内容进行删除,不过不是经常用
def price(self):
del self.__prix m1 = Market('洗发水',45,0.8)
print(m1.price)
m1.price = 48
print(m1.price)
del m1.price
print(m1.price)
将一个类的方法修改为私有方法,这样就伪装成属性,虽然在代码逻辑上没有什么提高,但是会让执行起来更合理一些,
4.类的多态
多态指的是一类事物有多种形态,比如:动物有多种形态:人,狗,猪
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
@abc.abstractmethod
def talk(self):
pass class People(Animal): #动物的形态之一:人
def talk(self):
print('say hello') class Dog(Animal): #动物的形态之二:狗
def talk(self):
print('say wangwang') class Pig(Animal): #动物的形态之三:猪
def talk(self):
print('say aoao')
4.1类的多态性
多态性是指在不考虑实例类型的情况下使用实例,多态性分为静态多态性和动态多态性
静态多态性:如任何类型都可以用运算符+进行运算
动态多态性:如下
peo=People()
dog=Dog()
pig=Pig() #peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk() #更进一步,我们可以定义一个统一的接口来使用
def func(obj):
obj.talk()
其实大家从上面多态性的例子可以看出,我们并没有增加什么新的知识,也就是说python本身就是支持多态性的,这么做的好处是什么呢?
- 增加了程序的灵活性:以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
- 增加了程序额可扩展性:通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
4.2鸭子方法
Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’
python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象
也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。
例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法
#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
def read(self):
pass def write(self):
pass class DiskFile:
def read(self):
pass
def write(self):
pass
day15-面向对象基础(二)的更多相关文章
- PYTHON开发--面向对象基础二
一.成员修饰符 共有成员 私有成员, __字段名 - 无法直接访问,只能间接访问 1. 私有成员 1.1 普通方法种的私有成员 class Foo: def __init__(self, n ...
- Java面向对象基础二
1.对象的用法 2.多对象的创建方法 3.匿名对象的创建和用法
- java面向对象基础(二)
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- Python基础:面向对象基础(二) 继承
子类在继承的时候,在定义类时,小括号()中为父类的名字,父类的属性.方法,会被继承给子类,Python中允许多继承. 多继承 # 父类 Master class Master(object): def ...
- Java学习 · 初识 面向对象基础二
Package 为什么需要使用package a) 解决类重名的问题 b) 便于管理类 怎么使用package a) 类的第一句非注释性语句 b) 命名:域名倒着写,再加上模块名 注意 ...
- 【重走Android之路】【Java面向对象基础(二)】细说String、StringBuffer和StringBuilder
[重走Android之路][基础篇(二)][Java面向对象基础]细说String.StringBuffer和StringBuilder 1.String String是Java中的一个final ...
- Python 基础 面向对象之二 三大特性
Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...
- MYSQL、PHP基础、面向对象基础简单复习总结
一.MYSQL 1.配置MySql 第一步安装服务器(apache). 第二部安装MySql界面程序 2 ...
- 从零开始学Python第六周:面向对象基础(需修改)
标签(空格分隔): 面向对象 一,面向对象基础 (1)面向对象概述 面向过程:根据业务逻辑从上到下写代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类 ...
- 8.python笔记之面向对象基础
title: 8.Python笔记之面向对象基础 date: 2016-02-21 15:10:35 tags: Python categories: Python --- 面向对象思维导图 (来自1 ...
随机推荐
- Chapter 4 Invitations——16
While I was sitting there, looking everywhere but at the car in front of me, I heard a knock on my p ...
- linux centos 安装Jenkins(非docker方式)
写在前面 我之前写过Asp.net Core 使用Jenkins + Dockor 实现持续集成.自动化部署(一):Jenkins安装这jenkisn的安装过程,但这篇使用的是docker的方式安装的 ...
- JdbcTemplate的一次爬坑记录
时隔三个多月,我终于想起我还有个博客,其实也不是忘了我这个博客,只是平时工作繁忙没时间去写博客,故今晚腾出时间来记录一下上次工作中遇到的一个问题,给园友们分享出来,以免入坑. 上个星期在工作中使用Jd ...
- SmartSql For Asp.Net Core 最佳实践
常规操作 安装 SmartSql Install-Package SmartSql 安装 SmartSql.DIExtension Install-Package SmartSql.DIExtensi ...
- 我和Session的不解之“缘”(故事型技术长文)
本文讲述了一路走来对Session的认知.文章有点长,不过是故事型的,应该不枯燥.相信读完也一定会有所收获. (一) “当你登陆系统后,服务器会创建一个Session,保存你的登陆信息,下次再访问时就 ...
- 痞子衡嵌入式:语音处理工具Jays-PySPEECH诞生记(5)- 语音识别实现(SpeechRecognition, PocketSphinx0.1.15)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是语音处理工具Jays-PySPEECH诞生之语音识别实现. 语音识别是Jays-PySPEECH的核心功能,Jays-PySPEECH借 ...
- 修复UEFI模式下Manjaro Linux启动问题
上周在更新Manjaro Linux的时候误触了电源键,导致内核更新了一半系统强制关机,重启时正常进入grub但无法正常引导进入系统. 由于不想重装系统(一大堆环境和工具的配置还是相当繁琐的),加上初 ...
- C# 如何获取Url的host以及是否是http
参考资料:https://sites.google.com/site/netcorenote/asp-net-core/get-scheme-url-host Example there's an g ...
- Java 学习笔记 观察者模式与适配者模式 监控文件夹
2019.4.12 适配器模式,如果某个类需要实现多个方法,但是开发过程中只需要实现其中的一两个方法,直接使用该类的适配器类,复写需要实现的方法即可 观察者模式:有多个观察者observe观察一个主体 ...
- 【学习笔记】非监督学习-k-means
目录 k-means k-means API k-means对Instacart Market用户聚类 Kmeans性能评估指标 Kmeans性能评估指标API Kmeans总结 无监督学习,顾名思义 ...