Python面向对象编程-02

Posted yangaoteng666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python面向对象编程-02相关的知识,希望对你有一定的参考价值。

本知识点参考廖雪峰的Python课程 [https://www.liaoxuefeng.com]

感谢北京图灵知非的免费课程 [http://www.tulingxueyuan.com/]

2018/6/26 星期二 11:15:57

继承和多态

  • 继承就是一个类可以获得另外一个类中的成员属性和成员方法
    • 作用: 减少代码,增加代码的复用功能, 同时可以设置类与类直接的关系
  • 继承与被继承的概念:
    • 被继承的类叫父类,也叫基类,也叫超类
    • 用于继承的类,叫子类,也叫派生类
    • 继承与被继承一定存在一个 is-a 关系
  • 继承的语法:

        class Animal(object):
            def run(self):
            print("Animal is runnung...")
        # Animal 继承于object,第一个类都继承于object,不管你写不写`object`
        class Dog(Animal):
            pass
        # Dog继承于Animal
        class Cat(Animal):
            pass
        # Cat继承于Animal
  • 对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类
  • 继承的好处就在于子类获得了父类的全部功能。Dog也有了AnimalRun() 方法

    >>> dog = Dog()
    # 子类一旦继承父类,则可以使用父类中除私有成员外的所有内容
    >>> dog.run
    Animal is runnung...
  • 我们对上面代码再次进行改进,给DogCat添加一些方法

        class Dog(Animal):
            def run(self):
                print(‘Dog is running...‘)
        class Cat(Animal):
            def run(self):
                print(‘Cat is running...‘)
  • 运行:

        >>> dog = Dog()
        >>> cat = Cat()
        >>> dog.run()
        >>> cat.run()
        Dog is running...
        Cat is running...
  • 我们可以看到这里,子类和父类都存在run方法时,子类的run()覆盖了父类的run().在代码运行的时候总会调用子类的run().这样我们就获得了继承的另外一个好处,多态。

    多态

  • 要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:

        a = list() # a是list类型
        b = Animal() # b是Animal类型
        c = Dog() # c是Dog类型
  • 判断一个变量是否是某个类型可以用isinstance()判断:

         >>> isinstance(a, list)
         True
         >>> isinstance(b, Animal)
         True
         >>> isinstance(c, Dog)
         True
  • 看来abc都对于着list、Animal、Dog这三种类型
  • 但是:

        >>> isinstance(c,Animal)
        True
  • 看来c不仅仅是Dog,c还是Animal
    不过仔细想想,这是有道理的,因为Dog是从Animal继承下来的,当我们创建了一个Dog的实例c时,我们认为c的数据类型是Dog没错,但c同时也是Animal也没错,Dog本来就是Animal的一种!
  • 所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:

        >>> b = Animal()
        >>> isinstance(b, Dog)
        False
  • 要理解多态的好处,我们编写一个函数

        def run_twice(animal):
            animal.run()
            animal.run()
  • 当我们传入Animal的实例时,run_twice()就打印出:

        >>> def run_twice(Animal()):
        Animal is running..
        Animal is running..
  • 当我们传入Dog的实例时,run_twice()就打印出:

        >>> def run_twice(Dog()):
        Dog is running..
        Dog is running..
  • 当我们传入Cat的实例时,run_twice()就打印出:

        >>> def run_twice(Cat()):
        Cat is running..
        Cat is running..
  • 如果我们再定义一个Tortoise类型,也从Animal派生:

        class Tortoise(Animal):
            def run(self):
                print(‘Tortoise is running slowly...‘)  
  • 当我们调用run_twice()时,传入Tortoise的实例:

        >>> run_twice(Tortoise())
        Tortoise is running slowly...
        Tortoise is running slowly...
  • 对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

    • 对扩展开放:允许新增Animal子类;
    • 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。

添加:

  • super()
  • 子类如果想扩充父类的方法,可以在定义新方法的同时访问父类成员来进行代码重用,可以使用 [父类名.父类成员] 的格式来调用父类成员,也可以使用super().父类成员的格式来调用。

        class Animal(object):
            def run(self):
            print("Animal is runnung...")
    
        class Dog(Animal):
            def run(self):
                print(‘Dog is running...‘)
        class Cat(Animal):
            def run(self):
                super().run()
                print(‘Cat is running...‘)
  • 继承变量函数的查找顺序问题
    • 优先查找自己的变量
    • 没有则查找父类
    • 构造函数如果本类中没有定义,则自动查找调用父类构造函数
    • 如果本类有定义,则不在继续向上查找
  • 构造函数
    • 是一类特殊的函数,在类进行实例化之前进行调用
    • 如果定义了构造函数,则实例化时使用构造函数,不查找父类构造函数
    • 如果没定义,则自动查找父类构造函数
    • 如果子类没定义,父类的构造函数带参数,则构造对象时的参数应该按父类参数构造

多继承于重继承

  • 继承面向对象编程的一个重要方式,通过继承,子类就可以扩展父类的功能
  • 如果我们把我们能想到的动物进行分类
    • Dog - 狗狗;
    • Bat - 蝙蝠;
    • Parrot - 鹦鹉;
    • Ostrich - 鸵鸟
  • 我们能飞的,能跑的,能游的,哺乳动物等分类,就太麻烦了,类的数量会指数级增长
  • 我们正确的做法是采用多重继承,首先主要层次任然安装哺乳动物,和鸟类分:

    class Animal(object):
        pass
    
    # 大类:
    class Mammal(Animal):
        pass
    
    class Bird(Animal):
        pass
    
    # 各种动物:
    class Dog(Mammal):
        pass
    
    class Bat(Mammal):
        pass
    
    class Parrot(Bird):
        pass
    
    class Ostrich(Bird):
        pass
  • 然后,我们在给动物加上Runnable和Flyable的功能,只需要先定义好Runnable和Flyable的类:

    class Runnable(object):
        def run(self):
            print(‘Running...‘)
    
    class Flyable(object):
        def fly(self):
            print(‘Flying...‘)

    -对于需要Runnable功能的动物,就多继承一个Runnable,例如Dog:

    class Dog(Mammal, Runnable):
        pass
  • 对于需要Flyable功能的动物,就多继承一个Flyable,例如Bat:

    class Bat(Mammal, Flyable):
        pass

    通过多重继承,一个子类就可以同时获得多个父类的所有功能。


  • Mixin
  • Mixin设计模式
  • 我们使用多继承语法来实现Minxin
  • 使用Mixin实现多继承的时候非常小心
    • 首先他必须表示某一单一功能,而不是某个物品
    • 职责必须单一,如果由多个功能,则写多个Mixin
    • Mixin不能依赖于子类的实现
    • 子类及时没有继承这个Mixin类, 也能照样工作,只是缺少了某个功能
  • 优点
    • 使用Mixin可以在不对类进行任何修改的情况下,扩充功能
    • 可以方便的组织和维护不同功能组件的划分
    • 可以根据需要任意调整功能类的组合
    • 可以避免创建很多新的类,导致类的继承混乱

以上是关于Python面向对象编程-02的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象编程-02

python04 面向对象编程02

Python面向对象编程02:深度认识类class

Python面向对象编程02:深度认识类class

Python中的面向对象编程(类编程)由简单到复杂的示例代码

02_python基础(面向对象编程)