zoukankan      html  css  js  c++  java
  • python学习第十五天 -面向对象之继承和多态

    大家都知道面向对象的三大特性:封装,继承,多态。封装特性在上一章节已经讲解过。这一章节主要讲解继承和多态。

    继承:

    当定义一个类的时候,可以从现有的类进行继承。那么新定义的类可以称为子类,被继承的现有的类称为基类,父类或者超类。

    上一章节大家应该有所注意以下代码:

    >>> class Animal(object):
        pass

    object类是python所有类的基类,Animal类是object类的子类。Animal类继承于object类。

    继承到底有什么好处?举个例子:

    >>> class Animal(object):
        def call(self):
            print('Animal is calling!')        
    >>> class dog(Animal):
        pass
    >>> dog = dog()
    >>> dog.call()
    Animal is calling!

    dog类继承了Animal类,当声明了一个dog实例对象后,可以直接调用父类Animal的call方法。

    这就是继承的好处,能够直接继承来自父类的属性和方法,然后直接调用。这样就精简了代码,提高了代码的复用性。

    如果父类在实例化对象的时候,要默认传入name参数的话,子类dog继承的时,应该怎么办?

    例子:

    >>> class Animal(object):
        def __init__(self,name):
            self.name = name
        def call(self):
            print ('Animal is calling!')
    
            
    >>> class dog(Animal):
        def __init__(self,name,birth):
            super(dog,self).__init__(name)//大家注意这句代码
            self.birth = birth
        def call(self):
            print ('dog is calling!')
    
            
    >>> dog = dog('wangcai','2016-8-5')
    >>> print dog.name
    wangcai
    >>> print dog.birth
    2016-8-5

    函数super(dog, self)将返回当前类继承的父类,即Animal,然后调用__init__()方法,注意self参数已在super()中传入,在__init__()中将隐式传递,不需要写出(也不能写).

    大家发现,dog子类也定义了一个call方法。那么实例化dog对象,dog.call()会发生什么?

    多态

    >>> dog.call()
    dog is calling!

    当子类和父类都存在相同的call()方法时,我们说,子类的call()覆盖了父类的call(),在代码运行的时候,总是会调用子类的call()。类似于C++的虚函数或者java的抽象方法。

    在理解多态之前,要判断一个对象/变量是否属于某一个类/类型,使用isinstance方法。

    >>> class Animal(object):
        def call(self):
            print('Animal is calling!')
    
            
    >>> class dog(Animal):
        def call(self):
            print('dog is calling!')
    
            
    >>> d =dog()
    >>> a =Animal()
    >>> isinstance(d,Animal)
    True
    >>> isinstance(a,dog)
    False

    看来,d不仅仅是dog,而且还是animal。而a 虽然是animal,但是不一定是dog,也有可能是cat。所以isinstance(a,dog)返回为false。

    所以在继承关系中,如果一个实例的数据类型是某个子类,那么它的数据类型也可以被看做是父类。所以isinstance(d,Animal)返回为True。

    有个上述的理解,那么我们再举个例子。

    >>> def lound_call(animal):
        animal.call()
    >>> lound_call(dog())
    dog is calling!
    >>> lound_call(Animal())
    Animal is calling!

    新增一个Animal子类cat。

    >>> class Cat(Animal):
        def call(self):
            print('cat is calling!')
    >>> lound_call(Cat())
    cat is calling!

    你会发现,新增一个Animal的子类,不必对lound_call()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

    多态的好处就是,当我们需要传入DogCat……时,我们只需要接收Animal类型就可以了,因为DogCat……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有call()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的call()方法,这就是多态的意思:

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

    对扩展开放:允许新增Animal子类;

    对修改封闭:不需要修改依赖Animal类型的lound_call()等函数。

    小结:这一章节主要讲解了python面向对象的属性继承和多态。

  • 相关阅读:
    [Sdoi2016]征途
    何时会发生db file sequential read等待事件?
    oracle分布式事务总结
    db file scattered read 等待事件
    db file sequential read (数据文件顺序读取)
    INDEX_JOIN
    Oracle优化器介绍
    GC Buffer Busy Waits处理(转载)
    Oracle V$SESSION详解
    Oracle锁表(转载)
  • 原文地址:https://www.cnblogs.com/nx520zj/p/5741906.html
Copyright © 2011-2022 走看看