热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python入门之面向对象之类继承与派生

本章内容一、继承二、抽象类三、继承的实现原理 一、继承1. 继承的定义 继承是一种新建类的方式,新建的类被称为子类,子类会继承父类的属性。在Python中支持,一个子类(派生类——

本章内容

    一、继承

    二、抽象类

    三、继承的实现原理

=======================================================

 

一、继承

  

  1. 继承的定义

 

    继承是一种新建类的方式,新建的类被称为子类,子类会继承父类的属性。

    在Python中支持,一个子类(派生类——可以继承一个或者多个父类(基类或者超类)

    

  2. 为什么要用继承

 

    继承可以有效减少代码冗余

 

  3. 如何使用继承

 

    继承代码示例

# 继承示例
class Father1:
        pass

class Father2:
        pass

class Son1(Father1):   # Son1继承Father1
    pass

class Son2(Father1,Father2):   # Son2同时继承Father1 & Father2
    pass

print(Son1.__bases__)
print(Son2.__bases__)

print(Father1.__bases__)
print(Father2.__bases__)

 

 

 

 

    以上代码的结果如下:

(<class '__main__.Father1'>,)                             #Son1继承Father1
(<class '__main__.Father1'>, <class '__main__.Father2'>)  #Son2继承Father1,Father2
(<class 'object'>,)        #Python3中有默认父类object
(<class 'object'>,)        #Python3中有默认父类object
# 在python3新建的类,默认都有一个父类(object) 

# 在python2中,默认是没有父类,可以添加(object)为父类

 

    

    需要注意Python2和Python3中关于类的分类是不一样的:

#Python2中的类:
#   
#   1.经典类
#        指的是没有继承默认父类object的类,以及没有继承object类的子类
#
#   2.新式类
#        值得是继承默认父类object以及object类子类的类
#
#
#Python3中的类:
#    
#    统一都是新式类

 

 

  4. 建立继承关系

 

    继承是类与类之间的关系,需要寻找这种关系,先进行抽象,然后建立继承

    子类所共有的特征,由父类进行统一配置管理

class SchoolPeople:
    
    school = 'SH high school'

    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
    
    def tell_info(self):
        print('School:Name is %s, Age is %s, Gender is %s' %(name,age,gender))

class SchoolStudent(SchoolPeople): #继承SchoolPeople

    def learn(self):
        print('%s is learning' %name)

    def tell_info(self):
        print('I'm student %s, Age is %s, Gender is %s ' %(name,age,gender))

class SchoolTeacher(schoolPeople):  #继承SchoolPeople

    def teach(self):
        print('%s is teaching' %name)
     
    def tell_info(self):
        print('I'm teacher %s, Age is %s, Gender is %s ' %(name,age,gender))

student1 = SchoolStudent('Bob','22','Male')
teacher1 = SchoolTeacher('Ajax','33','Female')

print(student1.__dict__)
print(student1.school)
print(teacher1.__dict__)

#子类已经自己定义tell_info()函数,显示格式将按照子类的格式显示,不需要按照父类的格式

student1.tell_info()
teacher1.tell_info()

 

 

    请仔细查看如下代码:

class Foo:
    def F1(self):
        print('Foo.F1')

    def F2(self):
        print('Foo.F2')
        self.F1()

class Bar(Foo):   #继承Foo
    def F1(self):   #子类中同时也有与父类同名的方法F1
        print('Bar.F1')

obj = Bar()
obj.F2()      
# obj先到父类Foo中找到F2方法运行
# 运行到self.F1()的时候会调用子类Bar自己的F1()方法,而不在调用父类的F1()方法

 

    以上显示的结果为:

Foo.F2
Bar.F1

 

  

  5. 子类派生出新的方法中重用父类的功能

 

   派生,是指子类定义自己新的属性,如果与父类同名,以子类自己的为准

 

    a. 调用父类方法,指名道姓的使用,请看如下代码

class SchoolPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def tell_info(self):
        print("""
        ===========个人信息==========
        姓名:%s
        年龄:%s
        性别:%s
        """ %(self.name,self.age,self.sex))


class SchoolTeacher(SchoolPeople):    # 继承SchoolPeople
    
    def __init__(self, name, age, sex, level, salary):
        # self.name = name
        # self.age = age
        # self.sex = sex
        SchoolPeople.__init__(self,name, age, sex)   # 点名指向SchoolPeople

        self.level = level
        self.salary = salary

    def tell_info(self):
    SchoolPeople.tell_info(self)     # 点名指向SchoolPeople
        print("""
        等级:%s
        薪资:%s
        """ %(self.level,self.salary))

tea1 = SchoolTeacher('Bob', 18, 'male', 9, 50k)
# print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)


tea1.tell_info()

 

 

    b. 调用父类方法,使用super()方法

      注意区分Python2和Python3中的super()的格式

      这种方法只能调用父类的方法

class SchoolPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def tell_info(self):
        print("""
        ===========个人信息==========
        姓名:%s
        年龄:%s
        性别:%s
        """ %(self.name,self.age,self.sex))


class SchoolTeacher(SchoolPeople):    # 继承SchoolPeople
    
    def __init__(self, name, age, sex, level, salary):
        # self.name = name
        # self.age = age
        # self.sex = sex
        super().__init__(self,name, age, sex)   # 使用super()指向父类,Python3的格式
        #super(SchoolPeople,self).__init__(self,name, age, sex)     Python2的格式
        self.level = level
        self.salary = salary

    def tell_info(self):
        super().tell_info(self)      # 使用super()指向父类,Python3的格式
        #super(SchoolPeople,self).tell_info(self)    Python2的格式
        print("""
        等级:%s
        薪资:%s
        """ %(self.level,self.salary))

tea1 = SchoolTeacher('Bob', 18, 'male', 9, 50k)
# print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)


tea1.tell_info()

 

 

 

二、抽象类

  

  主要使用abc模块,实现归一化,父类有的方法,子类必须有。

  需要在父类的方法头部加上@abc.abstractclassmethod

class File(metaclass=abc.ABCMeta):
    @abc.abstractmethod 
    def read(self):   #必须要定义下面的方法,如果没有就不让实例化
        pass
    @abc.abstractmethod
    def write(self):
        pass
class Sata(File):
    def read(self):
        pass
    def write(self):
        pass
    def asb(self):
        print('adsf')
Fil=Sata()
Fil.asb()
print(Sata.mro())

 

 

三、继承的实现原理

 

  1、继承顺序:

 

    经典类:当类是经典类时,多继承情况下,在要查找属性不存在时,会按照深度优先的方式查找下去

    新式类:当类是新式类时,多继承情况下,在要查询属性不存在时,会按照广度优先的方式查找下去

  

  2、方法解析顺序(Method Resolution Order, MRO)

  

    在多重继承中存在不相关的祖先类实现同名方法引起的冲突问题,这种问题称作“菱形问题”。

    Python依靠特定的顺序遍历继承图,这个顺序叫做方法解析顺序。

    如图,左图是类的UML图,右图中的虚线箭头是方法解析顺序:

Python入门之面向对象之类继承与派生

 

  3、使用属性来查看继承的顺序:

    print(类名.mro())

class A(object):
    # def test(self):
    #     print('from A')
    pass
 
class B(A):
    # def test(self):
    #     print('from B')
    pass
 
class C(A):
    # def test(self):
    #     print('from C')
    pass
class D(B):
    # def test(self):
    #     print('from D')
    pass
 
class E(C):
    # def test(self):
    #     print('from E')
    pass
class F(D,E):
    # def test(self):
    #     print('from F')
    pass
 
f1=F()
print(F.mro())

 

  4. 处理多重继承的建议

 

  (1)把接口继承和实现继承区分开;

    •   继承接口:创建子类型,是框架的支柱;

    •   继承实现:通过重用避免代码重复,通常可以换用组合和委托模式。

  (2)使用抽象基类显式表示接口;

  (3)通过混入重用代码;
    混入类为多个不相关的子类提供方法实现,便于重用,但不会实例化。并且具体类不能只继承混入类。

  (4)在名称中明确指明混入;
    Python中没有把类声明为混入的正规方式,Luciano推荐在名称中加入Mixin后缀。如Tkinter中的XView应变成XViewMixin。

  (5)抽象基类可以作为混入,反过来则不成立;
    抽象基类与混入的异同:

    •   抽象基类会定义类型,混入做不到;

    •   抽象基类可以作为其他类的唯一基类,混入做不到;

    •   抽象基类实现的具体方法只能与抽象基类及其超类中的方法协作,混入没有这个局限。

  (6)不要子类化多个具体类;
    具体类可以没有,或者至多一个具体超类。
    例如,Class Dish(China,Japan,Tofu)中,如果Tofu是具体类,那么China和Japan必须是抽象基类或混入。

  (7)为用户提供聚合类;
    聚合类是指一个类的结构主要继承自混入,自身没有添加结构或行为。Tkinter采纳了此条建议。

  (8)优先使用对象组合,而不是类继承。
    优先使用组合可以令设计更灵活。

  组合和委托可以代替混入,但不能取代接口继承去定义类型层次结构。

 


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 给定一个二维平面上的一些点,通过计算曼哈顿距离,求连接所有点的最小总费用。只有任意两点之间有且仅有一条简单路径时,才认为所有点都已连接。给出了几个示例并给出了对应的输出。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Allegro总结:1.防焊层(SolderMask):又称绿油层,PCB非布线层,用于制成丝网印板,将不需要焊接的地方涂上防焊剂.在防焊层上预留的焊盘大小要比实际的焊盘大一些,其差值一般 ... [详细]
  • Python入门后,想要从事自由职业可以做哪方面工作?1.爬虫很多人入门Python的必修课之一就是web开发和爬虫。但是这两项想要赚钱的话 ... [详细]
  • XMLhttpREquest_Ajax技术总结之XmlHttpRequest
    Ajax1、 什么是ajax   ... [详细]
  • asp.net(vb脚本)如何获取xml的节点值?xmlversion1.0encodingutf-8?rootimageimagemenusmenuurl#frame_paren ... [详细]
author-avatar
林白LS
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有