面向对象的组合用法

软件重用的重要方式除了继承之外还有另外一种方式,即:组合

组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合。

例:人狗大战,人类绑定上武器来对狗进行攻击:

# 定义一个武器类
class Weapon:
# 该武器的技能有劈砍
def cleave(self, target):
target.hp -= 50 # 劈砍技能对目标造成50点伤害 # 定义一个人类
class Person:
def __init__(self, name, sex, hp, atk):
self.name = name
self.sex = sex
self.hp = hp
self.atk = atk
self.weapon = Weapon() # 给角色绑定一个武器 # 定义一个狗类
class Dog:
def __init__(self, name, kind, hp, atk):
self.name = name
self.kind = kind
self.hp = hp
self.atk = atk # 实例化一个人类角色
tiele = Person('tiele', '男', 30, 10, )
# 实例化一个狗类角色
xiaobai = Dog('小白', '金毛寻回犬', 60, 15)
# 人类装备上武器使用武器技能cleave进行攻击狗类
tiele.weapon.cleave(xiaobai) # 这种用法就叫做组合
print(xiaobai.hp) # 显示10,表明目标的确hp-50了。

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系。比如人物有武器、有武学等。

当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。

再举一个老师有要教的课程和生日日期的例子如下:

class BirthDate:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day class Course:
def __init__(self, name, price, period):
self.name = name
self.price = price
self.period = period class Teacher:
def __init__(self, name, sex, birth, course):
self.name = name
self.sex = sex
self.birth = birth
self.course = course # 实例化一个老师的同时,传参的时候还可以传另一个实例化的对象
tiele = Teacher('铁乐', '男', BirthDate(1999, 4, 1), Course('python', '19800', '5 months'))
# 查看时可以直接用组合的方式查看
print(tiele.course.name, tiele.birth.year) # python 1999
print(tiele.course.price, tiele.birth.month) # 19800 4

面向对象的三大特性

分别是继承、多态、封装。

什么是继承?

继承是一种创建新类的方式,

在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,

新建的类称为派生类或子类。

python中类的继承分为:单继承和多继承。

class ParentClass1: #定义父类
pass class ParentClass2: #定义父类
pass #单继承,基类是ParentClass1,派生类是SubClass
class SubClass1(ParentClass1):
pass #python支持多继承,用逗号分隔开多个继承的类
class SubClass2(ParentClass1,ParentClass2):
pass # 查看继承
print(SubClass1.__bases__)
# __base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
# (<class '__main__.ParentClass1'>,)
print(SubClass2.__bases__)
# (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>) 如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,
它提供了一些常见方法(如__str__)的实现。 print(ParentClass1.__base__) # <class 'object'>
print(ParentClass2.__bases__) # (<class 'object'>,)

继承与抽象(先抽象再继承)

抽象即抽取类似或者说比较像的部分。

抽象分成两个层次:

1.将奥巴马和梅西这俩对象比较像的部分抽取成类;

2.将人,猪,狗这三个类比较像的部分抽取成父类。

抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,

才能通过继承的方式去表达出抽象的结构。

抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。

继承与重用性

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,

但是类B的大部分内容与类A的相同时

我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),

实现代码重用。

用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,

大大生了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,

也可以继承别人的,比如标准库,来定制新的数据类型,

这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.

派生

当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),

需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,

应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值.

在python3中,子类执行父类的方法也可以直接用super方法.

例:

class Animal:

    def __init__(self, name, hp, ad):
self.name = name # 对象属性 属性
self.hp = hp # 血量
self.ad = ad # 攻击力 def eat(self, target):
print('吃肉包子回血')
target.hp += 10 class Person(Animal): # 继承父类 def __init__(self, name, hp, ad, sex):
super().__init__(name, hp, ad)
# 使用super().__init__来继承父类属性的同时又可以同时有子类派生的属性
# 在单继承中,super负责找到当前类所在的父类,在这个时候不需要再手动传self
self.sex = sex
self.money = 0 # 派生属性 class Dog(Animal): def __init__(self, name, hp, ad, kind):
super().__init__(name, hp, ad)
self.kind = kind def bite(self, p): # 派生方法
p.hp -= self.ad
print('%s咬了%s一口,%s掉了%s点血' % (self.name, p.name, p.name, self.ad))
super().eat(self) # 使用super()---子类执行父类方法

super()

super 只有在子父类拥有同名方法的时候,

想使用子类的对象调用父类的方法时,才使用super

super在类内 : super().方法名(arg1,..)

指名道姓 :父类名.方法名(self,arg1,..)

在py2中super必须传参数 super(子类名,self).方法名(arg...)

在单继承中就是单纯的寻找父类;

在多继承中就是根据子节点 所在图 的 mro顺序找寻下一个类。

多继承 钻石继承

经典类: python2中有,不继承object,查找节点时遵循深度优先遍历算法;

新式类: python3中都是新式类,在py2中继承object,查找节点时遵循广度优先遍历算法;

广度优先:当一个节点可以在深度广度上都有机会被访问到的时候,优先从广度(横向)上查找。

类名.mro()方法可以查看广度优先的顺序;

super()的作用:在广度优先中查看当前这个类的上一个节点。

遇到多继承和super
对象.方法
找到这个对象对应的类
将这个类的所有父类都找到画成一个图
根据图写出广度优先的顺序
再看代码,看代码的时候要根据广度优先顺序图来找对应的super 经典类 :在python2.*版本才存在,且必须不继承object
遍历的时候遵循深度优先算法
没有mro方法
没有super()方法 新式类 :在python2.X的版本中,需要继承object才是新式类
遍历的时候遵循广度优先算法
在新式类中,有mro方法
有super方法,但是在2.X版本的解释器中,必须传参数(子类名,子类对象)

通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好。

end

2018-4-16

铁乐学python_day20_面向对象编程2的更多相关文章

  1. 铁乐学python_day22_面向对象编程4

    以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/ 封装 [封装]隐藏对象的属性和实现细节,仅对外提供公共访问方式. [好处] 将变化隔离: 便于使用: 提高复用性: 提 ...

  2. 铁乐学python_day18-19_面向对象编程1

    以下笔记绝大部分(百分之80或以上)摘自我的授课老师之一:老男孩教育中的景老师. 她上课讲的知识点由浅入深,引人入胜,听她的课完全不会感觉到困阿,而且不知不觉中就感觉掌握了. 她的博客是: http: ...

  3. 铁乐学python_day21_面向对象编程3

    抽象类和接口类 以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/ 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某 ...

  4. 铁乐学Python_Day33_网络编程Socket模块1

    铁乐学Python_Day33_网络编程Socket模块1 部份内容摘自授课老师的博客http://www.cnblogs.com/Eva-J/ 理解socket Socket是应用层与TCP/IP协 ...

  5. 铁乐学python_day24_面向对象进阶1_内置方法

    铁乐学python_day24_面向对象进阶1_内置方法 题外话1: 学习方法[wwwh] what where why how 是什么,用在哪里,为什么,怎么用 学习到一个新知识点的时候,多问问上面 ...

  6. 铁乐学python_day23_面向对象进阶1_反射

    铁乐学python_day23_面向对象进阶1_反射 以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/ isinstance()和issubclass() 两者的返回值 ...

  7. 洗礼灵魂,修炼python(34)--面向对象编程(4)—继承

    前面已经说到面向对象编程有封装,继承,多态三大特性,那么其中的继承则很重要,可以直接单独的拿出来解析 继承 1.什么是继承: 字面意是子女继承父母的家产或者特性等.而在编程里继承是指子类继承父类(基类 ...

  8. 铁乐学python_Day44_IO多路复用

    目录 IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) IO ...

  9. 铁乐学python_Day43_协程

    铁乐学python_Day43_协程 引子 之前我们学习了线程.进程的概念,了解了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位. 按道理来说我们已经算是把cpu的利用率提高很多了. ...

随机推荐

  1. 转:Java8内存模型—永久代(PermGen)和元空间(Metaspace)

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫“栈 ...

  2. 异常空格,ASCII (194,160)问题

    今天运营的同学反映有一些店铺的名称后面带空格,我下意识的说不可能啊,我已经处理过了啊.然后就找出来看. 其中有个店铺的名称是“安踏 ”,第一眼看上去好像是带了个空格.然后我就仔细的看了下. pry(m ...

  3. Windows 安装 MySQL 5.7.18

    1. 在MySQL官网 http://dev.mysql.com/downloads/mysql/ 上面下载ZIP安装包(第二个:Windows (x86, 64-bit), ZIP Archive) ...

  4. Dubbo2.7源码分析-SPI的应用

    SPI简介 SPI是Service Provider Interface的缩写,即服务提供接口(翻译出来好绕口,还是不翻译的好),实质上是接口,作用是对外提供服务. SPI是Java的一种插件机制,可 ...

  5. 哪个先执行:@PostConstruct和@Bean的initMethod?

    结论: /** * step1:执行构造函数 * step2:执行使用@PostConstruct注解修饰的方法[如果有多个,则执行顺序不确定] * step3:执行@Bean注解中initMetho ...

  6. 三种数据库访问——Spring3.2 + Hibernate4.2

    前三篇随笔中介绍了 用原生的JDBC访问数据库.一种高效的数据库连接池druid.用Spring的JDBC框架访问数据库. 本文继续介绍第三种数据库访问的解决方案:Spring3.2 + Hibern ...

  7. DataContractSerializer数据不一致下序列化

       一.数据类型的等效性 例如下面定义的两个类成员名称.定义顺序都不一样,但是在DataContract.DataMember的Name属性作用下,两个类的实例对象序列化后的xml是一样的,因此Or ...

  8. SQL SERVER 原来还可以这样玩 FOR XML PATH

    FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些以前可能需要借助函数活存储过程来完成的工作.那么以一个实例为主 ...

  9. springboot之约定大约配置

    前言 Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样 ...

  10. Vertica备份恢复

    Vertica备份和恢复数据库 Vertica提供了一个功能全面的使用程序--vbr, 他是一个Python脚本.使用vbr脚本可以备份和还原完整备份以及为特定架构或表创建备份.vbr实用程序会在首次 ...