zoukankan      html  css  js  c++  java
  • 第十章 单继承、多继承和魔术方法

    # 第十章 单继承、多继承和魔术方法
      说起生活中继承的概念,大家可能会说继承财产、继承家业和继承房子等继承别人的事件。那么,在Python编程世界里,类的继承又可以如何理解呢?
      
      所谓类的继承,就是在编写类时,并非要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一个类,它将自动获得另一个类的所有属性和方法。原来的类称为父类,而新类称为子类。从父类继承,可以直接拥有父类的属性和方法,这样可以减少代码,多复用,子类还可以定义自己的属性和方法。
    ## 一、类的单继承
    单继承:一个类只能继承一个父类的方式。
     
    ### 1、子类的方法__init__()
      创建子类的实例时,Python首先需要完成的任务就是给父类的所有属性赋值。为此,子类的方法__init__需要父类施以缓手。
      
      例如,下面来模拟一个父类为父亲子类为儿子的生活案例。儿子能继承学习父亲的习性,因此我们可以在前面创建的Father类的基础上创建新类Son,这样我们就只需要在继承父亲类后为特殊的属性和行为编写代码。
      
      创建一个简单的Father类。它具备Son类所有功能:
     
    执行该代码,结果为:
     
      首先是Father类的代码。创建子类时,父类必须包含在当前文件(Family.py)中,且位于子类前面.定义子类(Son)时,必须在括号内指定父类的名称。第十四行的方法__init__接受创建Father实例所需的信息。
      
      其中,super()是一个特殊的函数,帮助Python将父类和子类关联起来,这行代码让Python调用Son的父类的方法__init__(),让Son实例包含父类所有属性,父类也称为超类(superclass),名称super因此而得名。
      
      第十七行处,我们创建Son类的一个实例,并将其存储在变量在this_son中。调用了Son类中定义的方法__init__(),然后传入实参'yellow'和'black'。
      
      第十八行处,实例化对象this_son能够调用Father类的Behavior方法,继承Father类的行为。
      
    ### 2、给子类定义属性和方法
      
      让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
      
      下面来添加一个儿子特有的属性(age),以及一个描述该属性的方法。我们将存储这个属性,并编写一个打印这个描述该属性的方法:
     
     
    执行该代码,结果为:

      在十六行处,我们添加了新属性age,并设置了初始值16,根据Son类创建的实例都将包含这个属性,但所有Father都不包含它。在十八行处,我们还添加了一个名为Age的方法,打印出年龄的信息。

    ### 3、重写父类的方法
      对于父类的方法,只要它不符合子类模拟的实物的行为,都可对它进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注子类中定义的相应方法。
      
      假设Father类有一个名为语文成绩(Chinese)的方法,它对于父类毫无意义。所以你可能需要重写它。如下例:
      
     
      如果想调用方法Chinese(),Python将忽略Father类中的方法Chinese(),转而运行上述代码。使用继承时,可让子类保留从父类那里继承的精华,并剔除不必要的信息。
    ### 4、将实例用作属性
      使用代码模拟实物时,你可能会发现自己给类添加的字节越来越多,属性方法清单可能越来越长。在这种情况下,可能就需要将类的一部分作为一个独立的类提取出来。你可以将大型类拆分为协同工作的小类。
      
      例如,不断给Son添加细节时,我们会发现其中包含很多同龄人的爱好兴趣的属性和方法信息。在这种情况下,我们可以将这些属性和方法提取出来,放到另外一个名为Young类中,并将一个Young实例用作Son类的一个属性:
       
     
    执行该代码,结果为:
      在第一个红框处,我们定义了一个名为Young()的新类,它没有继承任何类。方法__init__()除了self外,还有另外一个形参age。这个形参是可选的:如果没有给它提供值,则默认被设置为16。子类Son的方法Age也被移到这个类中的yong_message()方法。
        
      在第二个红框处,我们添加了一个名为self.age的属性,这行代码让Python创建了一个新的Young实例,并将该实例存储在属性self.age中。每当方法__init__()被调用时,都将执行该操作,因此现在每个Son实例都包含一个自动创建的Yong实例。
      
      在第三个红框处,我们创建了一个变量this_son,要描述年龄信息时,需要使用Yong类的属性age。并且调用Yong实例的方法yong_message()。
      
      这看似做了很多额外的工作,但现在我们想要详细的信息都可以,并不会导致Son混乱不堪!
      
    ## 二、类的多继承
      多继承:一个类可以继承两个甚至多个父类的方式。当然一个子类有多个直接父类时,该子类会继承得到所有父类的方法。例如即有类A,类B,类C,C同时继承类A与类B,此时C中可以使用A与B中的属性与方法。那么问题来了,如果A与B中具有相同名字的方法,这个时候python调用的会是哪个方法呢?
      
      Python虽然语法上支持多继承,但是却不推荐使用多继承,而是推荐使用单继承,这样可以保证编程思路更清晰,也可以避免不必要的麻烦。
     
    执行该代码,结果为:
    如上代码,有多个父类包含同名方法会发生什么?此时排在前面的父类中的方法会“遮蔽”后面父类中的方法。  
     
    ## 三、类的魔术方法
      在Python中,所有以"__"双下划线包起来的方法,都统称为魔术方法,例如类的初始化方法__init__,销毁方法__del__。Python中所有的魔术方法均在官方文档中有相应描述,现在,我们来汇总下常见的魔术方法。
    ### 1、运算符方法
    - __add__(self,other)  #x+y
    - __sub__(self,other)  #x-y
    - __mlu__(self,other)  #x*y
    - __mod__(self,other)  #x%y
    - __radd__(self,other)  #y+x
    - __rsub__(self,other)  #y-x
    - __iadd__(self,other)  #x+=y  
    - __isub__(self,other)  #x-=y
    - __imlu__(self,other)  #x*=y
    - __imod__(self,other)  #x%=y
      执行该代码,结果为:
      
    ---
    17
     
    13
     
    ---
      在以上代码,第①行创建了一个名为MyClass的类,有三个方法,一个初始化方法__init__,两个加法运算方法。在十五行处,我们创建MyClass类的一个实例,并将其存储在变量在obj中,并传入一个实参5。接下来,当Python执行res=obj+2时,即使用对象进行运算相加的时候能够自动触发类中的魔术方法__add__()。
      
      而__add__()和__radd__()的不同就在于对象在运算符的左侧还是右侧,两者相对的位置不同就能触发两种不同的运算方式。那么,其他运算符魔术方法也可以自己课后练习了解一下。
    ### 2、类型转换方法
    - __bool__(self)      #调用bool(对象),将对象强制转为布尔类型
    - __complex__(self)   #调用complex(对象),将对象强制转为复数类型
    - __float__(self)       #调用int(对象),将对象强制转为浮点类型
    - __int__(self)       #调用int(对象),将对象强制转为整数类型
    执行该代码,结果为:
      
    ---
    False
     
    ---
    ### 3、容器类型方法
      - __len__(self)      #通过len(对象),执行类中的__len__()方法的len(属性)
      - __iner__(self)      #通过iner(对象),执行类中的__iner__()方法,迭代对象
      - __getitem__(self)  #通过getitem(对象),执行类中的__getitem__()方法,通过索引访问对象
    执行该代码,结果为:
      
    ---
    2
     
    ---
    ### 4、其他魔术方法
      - __class__() 查看类名
      - __base__() 查看继承的父类
      - __bases__() 查看继承的全部父类
      - __dict__() 查看全部属性,返回属性和属性值键值对形式
      - __doc__() 查看对象文档,即类中的注释
      - __dir__() 查看所有属性和方法
      
      还有很多,可以自查资料,了解学习一下。
        
    ## 四、课堂练习
    #### 1、现有如图所示的两个类,定义一个Child类继承这两个类,并且重写__init__方法,在实例化Child时候,调用ParentA类的__init__方法。
     
     
     
    #### 2、
     
    ## 五、上一节课堂练习答案
    #### 1、
     
     
    执行该代码,结果为:
     
     
    #### 2、定义一个类,实例化的时候打印'正在实例化',最后结束的时候,输出'正在销毁'。
     
    执行该代码,结果为:
     
    ---
    正在实例化
     
    正在销毁
     
    ---
     
     
      
     
     
     
     
    如有问题请留言,谢谢!
  • 相关阅读:
    mybaits不能出现小于号
    结合rpyc使用python实现动态升级的方法
    secureCRT使用小贴士
    大数据的实时技术
    gnuplot使用
    Python3.4使用MySql
    Linux内存分配----SLAB
    WinInet:HTTPS 请求出现无效的证书颁发机构的处理
    正则表达式学习
    C++中static的全部作用
  • 原文地址:https://www.cnblogs.com/yunsi/p/13203144.html
Copyright © 2011-2022 走看看