zoukankan      html  css  js  c++  java
  • 练习44-继承和组合

    有关继承的更多内容可参考:https://www.cnblogs.com/luoxun/p/13468850.html

    一  继承

    (1)什么是继承?

    • 功能:继承用来表明一个类将从其父类那里获得大多数或所有特性。
    • 交互方式:
      • 对子类的行为意味着对父类的行为。
      • 子类上的操作会覆盖父类上的操作。
      • 子类上的操作会更改父类上的操作。
    • 隐式继承(Implicit Inheritance):
      • 举例:
         1 class Parent(object):
         2     
         3     def implicit(self):
         4         print("PARENT implicit()")
         5 
         6 class Child(Parent):
         7     pass
         8 
         9 dad = Parent()
        10 son = Child()
        11 
        12 dad.implicit()
        13 son.implicit()
        ex44a.py
        这表明如果将函数放在基类中(比如Parent),然后所有子类(比如 Child)会自动获得这些特性。
      • 隐式调用函数的问题在于,有时你希望子类的行为有所不同。
    • 显示继承(Override Explicitly):
      • 举例:
         1 class Parent(object):
         2     
         3     def override(self):
         4         print("PARENT override()")
         5 
         6 class Child(Parent):
         7     
         8     def override(self):
         9         print("CHILD override()")
        10 
        11 dad = Parent()
        12 son = Child()
        13 
        14 dad.override()
        15 son.override()
        ex44b.py
        Child 通过定义它自己的版本来重写了那个函数。
    • 修改前后(使用super调用父类的方法)
      • 举例:
         1 class Parent(object):
         2     
         3     def altered(self):
         4         print("PARENT altered()")
         5 
         6 class Child(Parent):
         7     
         8     def altered(self):
         9         print("CHILD BEFORE PARENT altered()")
        10         super(Child,self).altered()
        11         print("CHILD AFTER PARENT altered()")
        12 
        13 dad = Parent()
        14 son = Child()
        15 
        16 dad.altered()
        17 son.altered()
        ex44c.py
      • 代码讲解:
        • 这里比较重要的是 9-11 行,在 Child 中,当调用 son.altered() 时,我其实做了以下事情:
          • 1. 因为在 Child.altered 版本运行时,我就重写了 Parent.altered 。第 9 行就按照你的预期执行了。
          • 2. 在这个例子中,我想做一个之前和之后的对比,所以在第 9 行之后,我想使用super 来获得 Parent.altered 版本。
          • 3. 在第10行,我调用 super(Child,self).altered() ,它意识到需要继承,并会为你获取 Parent 类。你应该能够把这个理解为“使用参数 Child 和 self 来调用 super,然后在它返回的任何地方调用 altered 函数”。
          • 4. 此时,Parent.altered 版本的函数运行,并打印出 Parent 的信息。
          • 5. 最后,它从 Parent.altered 返回。Child.altered 函数继续打印出之后的信息。
    • 三者结合
      • 举例:
         1 class Parent(object):                  # 父类
         2     
         3     def implicit(self):                # 用来表示隐式继承的方法,在子类中没有被重写
         4         print("PARENT implicit()")
         5     
         6     def override(self):                # 用来表示显示继承的方法,在子类中被重写,但是没有被通过super方法调用
         7         print("PARENT override()")
         8     
         9     def altered(self):                 # 用来表示显示继承的方法,在子类中不仅被重写还被super方法调用了
        10         print("PARENT altered()")
        11 
        12 class Child(Parent):                   # Child是子类,继承了Parent类,即Parent类中所有的方法Child类都可以直接调用
        13     
        14     def override(self):                # 重写父类中的override方法
        15         print("CHILD override()")
        16     
        17     def altered(self):                 # 重写父类中的altered方法
        18         print("CHILD BEFORE PARENT altered()")
        19         super(Child,self).altered()    # 使用super方法调用了父类的altered方法
        20         print("CHILD AFTER PARENT altered()")
        21 
        22 dad = Parent()                 # dad是父类Parent的对象
        23 son = Child()                  # son是子类Child的对象
        24 
        25 dad.implicit()                 # 通过父类类对象dad掉用父类中的implicit方法
        26 son.implicit()                 # 通过子类类对象son调用父类中的implicit方法
        27 
        28 dad.override()                 # 通过父类类对象dad掉用父类中的override方法
        29 son.override()                 # 通过子类类对象son调用子类中的override方法,该方法父类中也存在,但子类中对它进行了重写;此时子类的类对象son已经无法直接调用父类的override方法了
        30 
        31 dad.altered()                  # 通过父类类对象dad掉用父类中的altered方法
        32 son.altered()                  # 通过子类类对象son调用子类中的altered方法,子类对父类的altered方法进行了重写,并在重写过程中用super方法调用了父类的方法,同时子类的类对象son无法直接调用父类的altered方法
        ex44d.py

    (2)super方法

    • 多重继承:指你定义了一个继承自一个或多个类的类
    • 语法:
      1 class SuperFun (Child, BadStuff):
      2     pass
    • 问题:在这种情况下,每当你对任何 SuperFun 的实例执行隐式操作时,Python 都必须在 Child 类和BadStuff 类的层级结构中查找可能的函数,不过它需要以一致的顺序来执行这项操作。
    • 解决办法:Python 使用了“方法解析顺序”(method resolution order,MRO)和一种被称为 C3 的算法;但它非常复杂,Python不能让你自己来处理 MRO。
    • 最终结果:提供了 super() 函数,它可以在你需要更改类似动作的地方为你解决这个问题;使用 super() ,你不用担心是否正确,Python 会为你找到正确的函数。
    • 常用用法:——用 __init__ 来使用 super()
      • 用途:super() 最常用的用法其实是在基类中使用 __init__ 函数。这通常是你在一个子类中唯一需要做一些操作,然后在父类中完成初始化的地方。
      • 举例:
        1 class Child (Parent):
        2 
        3     def __init__(self, stuff):
        4         self.stuff = stuff
        5         super(Child, self).__init__( ) 

    二 组合

    • 组合:继承很有用,但是还有一种能实现相同效果的方法,就是使用其他类和模块,而不是依赖于隐式继承。
    • 举例:
       1 class Other(object):
       2     
       3     def implicit(self):
       4         print("OTHER implicit()")
       5     
       6     def override(self):
       7         print("OTHER override()")
       8     
       9     def altered(self):
      10         print("OTHER altered()")
      11 
      12 class Child(object):
      13     
      14     def __init__(self):
      15         self.other = Other()
      16     
      17     def implicit(self):
      18         self.other.implicit()
      19     
      20     def override(self):
      21         print("CHILD override()")
      22     
      23     def altered(self):
      24         print("CHILD BEFORE PARENT altered()")
      25         self.other.altered()
      26         print("CHILD AFTER PARENT altered()")
      27 
      28 son = Child()
      29 
      30 son.implicit()
      31 son.override()
      32 son.altered()
      ex44e.py
      在这段代码中,我没有使用 Parent 这个名字,因为不存在父子 is-a 关系,而是一个 has-a 关系,其中 Child 有一个(has-a) Other 来完成它的工作。
    • 可以看到,Child 和 Other 中的大多数代码都是相同的,可以完成相同的事情。唯一的区别是我必须定义一个 Child.implicit 函数来完成这个动作。然后我可以问自己是否需要这个 Other 作为一个类,我是否可以将它放入一个名为 Other.py 的模块中?

    三 什么时候使用继承和组合?

    • “继承与组合”的问题可以归结为试图解决可复用代码的问题。
      • 继承通过在基类中创建隐含特性的机制来解决这个问题。
      • 组合通过提供模块以及调用其他类中的函数来解决这个问题
    • 怎么区分使用:
      • 无论如何都要避免多重继承,因为它太复杂而且不可靠。如果你被它困住了,那么要准备好了解一下类的层次结构,并花时间找出所有内容的来源。
      • 使用组合将代码打包到模块中,这些模块可以用于许多不同的、不相关的地方和情境。
      • 只有当存在明显相关的可复用代码片段,并且这些代码片段符合单个通用概念,或者由于你使用了某些东西而别无选择时,你才可以使用继承。
    • 关于面向对象编程,需要记住的一点是,它完全是程序员为了打包和共享代码而创建的一种社会约定。因为这是一种社会惯例,并且在 Python 中已经形成了这种惯例,你可能会因为与你一起工作的人而被迫绕过这些规则。在这种情况下,弄明白他们是如何使用每一种东西,然后努力适应这种情况。
    • 对象不就是类的拷贝吗? 在某些语言中(如 JavaScript),这是对的。这些被称为原型语言,除了用法之外,对象和类之间没有太多区别。然而,在 Python 中,类充当“铸造”(mint)新对象的模板,类似于使用模具(die) 来铸造硬币的概念。
  • 相关阅读:
    Jenkins构建项目
    jenkins的理解及安装
    GitLab初识以及代码迁移
    深入浅出Git(偏向理论)
    理解下所谓的ssh隧道
    洛谷-P1908 逆序对
    洛谷-P1010 幂次方
    洛谷-P1226 【模板】快速幂||取余运算
    洛谷-P1074 靶形数独
    洛谷-P1433 吃奶酪
  • 原文地址:https://www.cnblogs.com/luoxun/p/13476773.html
Copyright © 2011-2022 走看看