zoukankan      html  css  js  c++  java
  • python3中的继承和多态

    *继承

    当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

    比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:

    class Animal(object):

        def run(self):
            print('Animal is running...')

    当我们需要编写DogCat类时,就可以直接从Animal类继承:
    class Dog(Animal):
        pass
    
    class Cat(Animal):
        pass
    

    对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。CatDog类似。

    继承有什么好处?最大的好处是子类获得了父类的全部功能。由于Animial实现了run()方法,因此,DogCat作为它的子类,什么事也没干,就自动拥有了run()方法

    如下所示

    dog = Dog()
    dog.run()
    
    cat = Cat()
    cat.run()

    运行结果如下:
    Animal is running...
    Animal is running...
    当然,也可以对子类增加一些方法,比如对Cat类
    class Cat(Animal):
    
        def run(self):
            print('Dog is running...')
    
        def eat(self):
            print('Eating meat...')
    
    需要注意的是:当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态。

    继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:

                    ┌───────────────┐
                    │    object     │
                    └───────────────┘
                            │
               ┌────────────┴────────────┐
               │                         │
               ▼                         ▼
        ┌─────────────┐           ┌─────────────┐
        │   Animal    │           │    Plant    │
        └─────────────┘           └─────────────┘
               │                         │
         ┌─────┴──────┐            ┌─────┴──────┐
         │            │            │            │
         ▼            ▼            ▼            ▼
    ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
    │   Dog   │  │   Cat   │  │  Tree   │  │ Flower  │
    └─────────┘  └─────────┘  └─────────┘  └─────────┘
    


    *多态
    要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个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确实对应着listAnimalDog这3种类型。

    但是等等,试试:

    >>> isinstance(c, Animal)
    True
    

    看来c不仅仅是Dogc还是Animal

    不过仔细想想,这是有道理的,因为Dog是从Animal继承下来的,当我们创建了一个Dog的实例c时,我们认为c的数据类型是Dog没错,但c同时也是Animal也没错,Dog本来就是Animal的一种!

    所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:

    >>> b = Animal()
    >>> isinstance(b, Dog)
    False
    

    Dog可以看成Animal,但Animal不可以看成Dog

    要理解多态的好处,我们还需要再编写一个函数,这个函数接受一个Animal类型的变量:

    def run_twice(animal):
        animal.run()
        animal.run()
    

    当我们传入Animal的实例时,run_twice()就打印出:

    >>> run_twice(Animal())
    Animal is running...
    Animal is running...
    

    当我们传入Dog的实例时,run_twice()就打印出:

    >>> run_twice(Dog())
    Dog is running...
    Dog is running...
    

    当我们传入Cat的实例时,run_twice()就打印出:

    >>> 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_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

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

    *动态语言与静态语言的区别

    静态语言

    对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

    动态语言

    对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了。

    这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

    就是说只要有一个方面相似,就能继承。

    小结:
    继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
     
  • 相关阅读:
    《C# to IL》第一章 IL入门
    multiple users to one ec2 instance setup
    Route53 health check与 Cloudwatch alarm 没法绑定
    rsync aws ec2 pem
    通过jvm 查看死锁
    wait, notify 使用清晰讲解
    for aws associate exam
    docker 容器不能联网
    本地运行aws lambda credential 配置 (missing credential config error)
    Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?
  • 原文地址:https://www.cnblogs.com/tanshengjiang/p/11679344.html
Copyright © 2011-2022 走看看