今天整理类的组合以及类的三大特性

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-面向对象基础(二)的更多相关文章

  1. PYTHON开发--面向对象基础二

    一.成员修饰符 共有成员 私有成员, __字段名 - 无法直接访问,只能间接访问 1.     私有成员 1.1  普通方法种的私有成员 class Foo: def __init__(self, n ...

  2. Java面向对象基础二

    1.对象的用法 2.多对象的创建方法 3.匿名对象的创建和用法

  3. java面向对象基础(二)

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  4. Python基础:面向对象基础(二) 继承

    子类在继承的时候,在定义类时,小括号()中为父类的名字,父类的属性.方法,会被继承给子类,Python中允许多继承. 多继承 # 父类 Master class Master(object): def ...

  5. Java学习 · 初识 面向对象基础二

    Package 为什么需要使用package a)   解决类重名的问题 b)   便于管理类 怎么使用package a)   类的第一句非注释性语句 b)   命名:域名倒着写,再加上模块名 注意 ...

  6. 【重走Android之路】【Java面向对象基础(二)】细说String、StringBuffer和StringBuilder

    [重走Android之路][基础篇(二)][Java面向对象基础]细说String.StringBuffer和StringBuilder   1.String String是Java中的一个final ...

  7. Python 基础 面向对象之二 三大特性

    Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...

  8. MYSQL、PHP基础、面向对象基础简单复习总结

    一.MYSQL         1.配置MySql                 第一步安装服务器(apache).                 第二部安装MySql界面程序         2 ...

  9. 从零开始学Python第六周:面向对象基础(需修改)

    标签(空格分隔): 面向对象 一,面向对象基础 (1)面向对象概述 面向过程:根据业务逻辑从上到下写代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类 ...

  10. 8.python笔记之面向对象基础

    title: 8.Python笔记之面向对象基础 date: 2016-02-21 15:10:35 tags: Python categories: Python --- 面向对象思维导图 (来自1 ...

随机推荐

  1. [Python Web]常见的 POST 提交数据的方式

    本文参考整理于:https://imququ.com/post/four-ways-to-post-data-in-http.html 简介 这里介绍了,用 POST 方法提交数据时,常见的三种方式: ...

  2. Linux~常用的命令

    大叔学Linux就一个目的,部署在它上面的服务,如redis,mongodb,fastDFS,cat,docker,mysql,nginx等 下面找一下的命令,来学学这个神秘的操作系统 常用指令 ls ...

  3. 使用docker-compose来部署开发环境

    docker-compose的作用 docker-comopse可以帮助我们快速搭建起开发环境,比如你可以去把redis,mongodb,rabbitmq,mysql,eureka,configser ...

  4. Unity实现c#热更新方案探究(三)

    转载请标明出处:http://www.cnblogs.com/zblade/ 前面两篇文章从头到尾讲解了C#热更新的一些方案,从程序域来加载和卸载DLL,到使用ILRuntime来实现安卓和IOS平台 ...

  5. RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)

    在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...

  6. 4.计算机启动过程的简单介绍 计算机启动流程 计算机BIOS作用 POST 开机自检 计算机启动顺序 分区表 操作系统启动

    计算机的启动

  7. 痞子衡嵌入式:第一本Git命令教程(7.1)- 清理之缓存(stash)

    今天是Git系列课程第七课,上一课我们学会了查看Git本地历史提交,今天痞子衡要讲的是Git仓库的清理操作,一共4个命令,都是日常开发中非常实用的命令,掌握这4个命令,会让你有一种玩弄Git仓库于股掌 ...

  8. selenium加载配置参数,让chrome浏览器不出现‘Chrome正在受到自动软件的控制’的提示语,以及后台静默模式启动自动化测试,不占用桌面的方法

    一:自动化测试的时候,启动浏览器出现‘Chrome正在受到自动软件的控制’,怎么样隐藏,今天学习分享: 在浏览器配置里加个参数,忽略掉这个警告提示语,disable_infobars option = ...

  9. .Net语言 APP开发平台——Smobiler学习日志:如何快速实现按钮组功能

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的“Smobil ...

  10. 从零开始学安全(三十九)●FCK编辑器解析漏洞

    fck 现在存在漏洞的本版分别是 2.4.2 ,2.4.4,2.6.6 可以在 查看版本 2.4.2 在 图片域有上传点 2.4.4 这里有几个按钮,首先是 Get Folders and Files ...