一文了解什么是Python面向对象中的继承

1、什么是继承?

继承指的是类与类之间的关系,是一种什么是什么的关系,功能之一就是用来解决代码重用问题。

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类,继承又分为单继承和多继承。

class ParentClass1: #定义父类
    pass
class ParentClass2: #定义父类
    pass
class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
    pass
class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
    pass
print(Son1.__bases__)  # 查看所有继承的父类
print(Son2.__bases__)
===============
(<class '__main__.Father1'>,)
(<class '__main__.Father1'>, <class '__main__.Father2'>)

2、继承与抽象

抽象分成两个层次:

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

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

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

1566984641(1).png

继承:

是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

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

1566984624(1).png

class animal():   # 定义父类
    country  =  'china'     # 这个叫类的变量
    def __init__(self,name,age):
        self.name=name   # 这些又叫数据属性
        self.age=age
    def walk(self):         # 类的函数,方法,动态属性
        print('%s is walking'%self.name)
    def say(self):
        pass
class people(animal):  # 子类继承父类
    pass
class pig(animal):    # 子类继承父类
    pass
class dog(animal):  # 子类继承父类
    pass
aobama=people('aobama',60)   # 实例化一个对象
print(aobama.name)
aobama.walk()
===================
aobama
aobama is walking

3、派生

1.在父类的基础上产生子类,产生的子类就叫做派生类。

2.父类里没有的方法,在子类中有了,这样的方法就叫做派生方法。

3.父类里有,子类也有的方法,就叫做方法的重写(就是把父类里的方法重写了)。

相关推荐:《Python视频教程

例1

class Hero:
    def __init__(self, nickname,
                 aggressivity,
                 life_value):
        self.nickname = nickname
        self.aggressivity = aggressivity
        self.life_value = life_value
    def attack(self, enemy):
        enemy.life_value -= self.aggressivity
class Garen(Hero):   # 子类继承  hero 父类
    camp='Demacia'   # 子类衍生出的变量
    def attack(self, enemy):   # 跟父类的 attack 重名,对象调用的时候以子类的为准
        pass
    def fire(self):    # 父类没有 fire,这里 fire 属于派生出来的东西
        print('%s is firing' %self.nickname)
class Riven(Hero):
    camp='Noxus'
g1=Garen('garen',18,200)
r1=Riven('rivren',18,200)
# print(g1.camp)
# print(r1.camp)
# g1.fire()
g1.attack(g1)

例2

class Hero:
    def __init__(self, nickname,aggressivity,life_value):
        self.nickname = nickname
        self.aggressivity = aggressivity
        self.life_value = life_value
    def attack(self, enemy):
        print('Hero attack')
class Garen(Hero):
    camp = 'Demacia'
    def attack(self, enemy): #self=g1,enemy=r1
        # self.attack(enemy) #g1.attack(r1),这里相当于无限递归
        Hero.attack(self,enemy)  # 引用 父类的 attack,对象会去跑 父类的 attack
        print('from garen attack')  # 再回来这里
    def fire(self):
        print('%s is firing' % self.nickname)
class Riven(Hero):
    camp = 'Noxus'
g1 = Garen('garen', 18, 200)
r1 = Riven('rivren', 18, 200)
g1.attack(r1)
# print(g1.camp)
# print(r1.camp)
# g1.fire()

4、组合与重用性

重用性:

方式1:不通过继承的方式重用属性,指名道姓的使用哪个类的属性。

class Hero:
    def __init__(self,nickname,gongji,life):
        self.nickname=nickname
        self.gongji=gongji
        self.life=life
    def attack(self,obj):
        print('from Hero attack')
class Garen:
    def __init__(self,nickname,gongji,life,script):
        Hero.__init__(self,nickname,gongji,life)   # 这里引用Hero类的 init,不用再自己从新定义一遍 init
        self.script=script   # 父类 init 没有 script,这里是新加进来的属性
    def attack(self,obj):  # 在这里自己定义新的 attack,不再使用父类的 attack
        print('from Garen attack')
    def fire(self):  # 在这里定义新的功能
        print('from Garen fire')
g1=Garen('garen',18,200,'人在塔在')
print(g1.script)
人在塔在

提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分甚至大部分,大大省了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大。

注意:像g1.life之类的属性引用,会先从实例中找life,然后去类中找,然后再去父类中找...直到最顶级的父类。

方式2:通过继承

例1

class Hero():
    def __init__(self, nickname, gongji, life):
        self.nickname = nickname
        self.gongji = gongji
        self.life = life
    def attack(self, obj):
        print('from Hero attack')
        obj.life -= self.gongji
class Garen(Hero):   # 使用 super方式需要继承
    camp = 'Demacia'
    def __init__(self, nickname, gongji, life):
        super().__init__(nickname, gongji, life)
    def attack(self, obj):  # 在这里自己定义新的 attack,不再使用父类的 attack
        super(Garen, self).attack(obj)  # PY3中super可以不给参数,PY2中第一个参数必须是自己的类,self,可以使用
        父类的方法,方法需要给参数就给参数
    def fire(self):  # 在这里定义新的功能
        print('from Garen fire')
g1 = Garen('garen1', 18, 200)
g2 = Garen('garen2', 20, 100)
print(g2.life)
g1.attack(g2)
print(g2.life)
100
from Hero attack
82

例2

class A:
    def f1(self):
        print('from A')
        super().f1()    
        # 这种不需要继承也可以使用到 super,为什么,要看 C的 MRO表
class B:
    def f1(self):
        print('from B')
class C(A,B):
    pass
print(C.mro())
#[<class '__main__.C'>,
# <class '__main__.A'>,
# <class '__main__.B'>, #  B在A的后面,当A指定 super().f1 会找到 B的 f1
# <class 'object'>]
c=C()
c.f1()

组合:

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

组合:一个对象的数据属性是另一个对象,称为组合。

class Equip: #武器装备类
    def fire(self):
        print('release Fire skill')
class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
    camp='Noxus'
    def __init__(self,nickname):
        self.nickname=nickname
        self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
r1=Riven('锐雯雯')
r1.equip.fire() #可以使用组合的类产生的对象所持有的方法
release Fire skill

组合的方式:

组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同。

1.继承的方式

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

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

2.组合的方式

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

class People:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
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))
class Teacher(People):
    def __init__(self,name,age,sex,job_title):
        People.__init__(self,name,age,sex)
        self.job_title=job_title
        self.course=[]
        self.students=[]
class Student(People):
    def __init__(self,name,age,sex):
        People.__init__(self,name,age,sex)
        self.course=[]
egon=Teacher('egon',18,'male','沙河霸道金牌讲师')
s1=Student('牛榴弹',18,'female')
python=Course('python','3mons',3000.0)
linux=Course('python','3mons',3000.0)
#为老师egon和学生s1添加课程
egon.course.append(python)
egon.course.append(linux)
s1.course.append(python)
#为老师egon添加学生s1
egon.students.append(s1)
#使用
for obj in egon.course:
    obj.tell_info()

5、接口与归一化设计

a、为何要用接口?

接口提取了一群类共同的函数,可以把接口当做一个函数的集合。

然后让子类去实现接口中的函数。

这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。

归一化的好处在于:

归一化让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。
    def read(self): #定接口函数read
        pass
    def write(self): #定义接口函数write
        pass
class Txt(Interface): #文本,具体实现read和write
    def read(self):
        print('文本数据的读取方法')
    def write(self):
        print('文本数据的读取方法')
class Sata(Interface): #磁盘,具体实现read和write
    def read(self):
        print('硬盘数据的读取方法')
    def write(self):
        print('硬盘数据的读取方法')
class Process(Interface):
    def read(self):
        print('进程数据的读取方法')
    def write(self):
        print('进程数据的读取方法')

上面的代码只是看起来像接口,其实并没有起到接口的作用,子类完全可以不用去实现接口,这就用到了抽象类。

6、抽象类

子类必须继承抽象类的方法,不然报错。

什么是抽象类?

与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

为什么要有抽象类?

如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。你永远无法吃到一个叫做水果的东西。

从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。

抽象类与接口

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。

例1

import abc
#抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们
class Animal(metaclass=abc.ABCMeta):   # 抽象类是用来被子类继承的,不是用来实例化的
    tag='123123123123123'
    @abc.abstractmethod   # 如果子类没有我这个函数,主动抛出异常
    def run(self):
        pass
    @abc.abstractmethod
    def speak(self):
        pass
class People(Animal):
    def run(self):   # 子类必须有抽象类里的装饰器下面的函数
        pass
    def speak(self):
        pass
peo1=People()   # 实例化出来一个人
print(peo1.tag)

例2

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#一切皆文件
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def read(self):
        '子类必须定义读功能'
        pass
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def write(self):
        '子类必须定义写功能'
        pass
# class Txt(All_file):
#     pass
#
# t1=Txt() #报错,子类没有定义抽象方法
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('文本数据的读取方法')
    def write(self):
        print('文本数据的读取方法')
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('硬盘数据的读取方法')
    def write(self):
        print('硬盘数据的读取方法')
class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('进程数据的读取方法')
    def write(self):
        print('进程数据的读取方法')
wenbenwenjian=Txt()
yingpanwenjian=Sata()
jinchengwenjian=Process()
#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()
print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Python中的函数(二) 在上一篇文章中提到了Python中函数的定义和使用,在这篇文章里我们来讨论下关于函数的一些更深的话题。在学习C语言函数的时候,遇到的问题主要有形参实参的区别、参数的传递和改变、变量的作用域。同样在Python中,关于对函数的理解和使用也存在这些问题。下面来逐一讲解。一.函
Python中的字符串 可能大多数人在学习C语言的时候,最先接触的数据类型就是字符串,因为大多教程都是以&quot;Hello world&quot;这个程序作为入门程序,这个程序中要打印的&quot;Hello world&quot;就是字符串。如果你做过自然语言处理方面的研究,并且用Python
Python 面向对象编程(一) 虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程。下面就来了解一下如何在Python中进行对象编程。一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法。 类是对现实世界中一些事物的封装,
Python面向对象编程(二) 在前面一篇文章中谈到了类的基本定义和使用方法,这只体现了面向对象编程的三大特点之一:封装。下面就来了解一下另外两大特征:继承和多态。 在Python中,如果需要的话,可以让一个类去继承一个类,被继承的类称为父类或者超类、也可以称作基类,继承的类称为子类。并且Pytho
Python中的函数(一) 接触过C语言的朋友对函数这个词肯定非常熟悉,无论在哪门编程语言当中,函数(当然在某些语言里称作方法,意义是相同的)都扮演着至关重要的角色。今天就来了解一下Python中的函数用法。一.函数的定义 在某些编程语言当中,函数声明和函数定义是区分开的(在这些编程语言当中函数声明
在windows下如何快速搭建web.py开发框架 用Python进行web开发的话有很多框架供选择,比如最出名的Django,tornado等,除了这些框架之外,有一个轻量级的框架使用起来也是非常方便和顺手,就是web.py。它由一名黑客所创建,但是不幸的是这位创建者于2013年自杀了。据说现在由
将Sublime Text 2搭建成一个好用的IDE 说起编辑器,可能大部分人要推荐的是Vim和Emacs,本人用过Vim,功能确实强大,但是不是很习惯,之前一直有朋友推荐SUblime Text 2这款编辑器,然后这段时间就试了一下,就深深地喜欢上这款编辑器了...
Python中的模块 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt这个函数,必须用语句&quot;#include&lt;math.h&gt;&quot;引入math.h这个头文件,否则是无法正常进行调用的。那么在Python中,如果要引用一些内置的函数,该怎么处理呢?在Python中
Python的基础语法 在对Python有了基础的认识之后,下面来了解一下Python的基础语法,看看它和C语言、java之间的基础语法差异。一.变量、表达式和语句 Python中的语句也称作命令,比如print &quot;hello python&quot;这就是一条语句。 表达式,顾名思义,是
Eclipse+PyDevʽjango+Mysql搭建Python web开发环境 Python的web框架有很多,目前主流的有Django、Tornado、Web.py等,最流行的要属Django了,也是被大家最看好的框架之一。下面就来讲讲如何搭建Django的开发环境。一.准备工作 需要下载的
在windows下安装配置Ulipad 今天推荐一款轻便的文本编辑器Ulipad,用来写一些小的Python脚本非常方便。 Ulipad下载地址: https://github.com/limodou/ulipad http://files.cnblogs.com/dolphin0520/u...
Python中的函数(三) 在前面两篇文章中已经探讨了函数的一些相关用法,下面一起来了解一下函数参数类型的问题。在C语言中,调用函数时必须依照函数定义时的参数个数以及类型来传递参数,否则将会发生错误,这个是严格进行规定的。然而在Python中函数参数定义和传递的方式相比而言就灵活多了。一.函数参数的
在Notepad++中搭配Python开发环境 Python在最近几年一度成为最流行的语言之一,不仅仅是因为它简洁明了,更在于它的功能之强大。它不仅能够完成一般脚本语言所能做的事情,还能很方便快捷地进行大规模的项目开发。在学习Python之前我们来看一下Python的历史由来,&quot;Pytho
Python中的条件选择和循环语句 同C语言、Java一样,Python中也存在条件选择和循环语句,其风格和C语言、java的很类似,但是在写法和用法上还是有一些区别。今天就让我们一起来了解一下。一.条件选择语句 Python中条件选择语句的关键字为:if 、elif 、else这三个。其基本形式如
关于raw_input( )和sys.stdin.readline( )的区别 之前一直认为用raw_input( )和sys.stdin.readline( )来获取输入的效果完全相同,但是最近在写程序时有类似这样一段代码:import sysline = sys.stdin.readline()
初识Python 跟学习所有的编程语言一样,首先得了解这门语言的编程风格和最基础的语法。下面就让我们一起来了解一下Python的编程风格。1.逻辑行与物理行 在Python中有逻辑行和物理行这个概念,物理行是指在编辑器中实际看到的一行,逻辑行是指一条Python语句。在Python中提倡一个物理行只
当我们的代码是有访问网络相关的操作时,比如http请求或者访问远程数据库,经常可能会发生一些错误,有些错误可能重新去发送请求就会成功,本文分析常见可能需要重试的场景,并最后给出python代码实现。
1.经典迭代器 2.将Sentence中的__iter__改成生成器函数 改成生成器后用法不变,但更加简洁。 3.惰性实现 当列表比较大,占内存较大时,我们可以采用惰性实现,每次只读取一个元素到内存。 或者使用更简洁的生成器表达式 4.yield from itertools模块含有大量生成器函数可
本文介绍简单介绍socket的常用函数,并以python-kafka中的源码socketpair为例,来讲解python socket的运用
python实践中经常出现编码相关的异常,大多网上找资料而没有理解原理,导致一次次重复错误。本文对常用Unicode、UTF-8、GB2312编码的原理进行介绍,接着介绍了python字符类型unicode和str以及常见编解码错误UnicodeEncodeError和UnicodeDEcodeEr