zoukankan      html  css  js  c++  java
  • 面对对象三大特征:继承 多态(鸭子类型)(面试题)

    继承:至少两个类: 什么是什么的关系,为了避免几个类之间有相同的代码

    组合:什么有什么的关系

    父类:基类或超类

     

    通过继承创建的新类称为“子类”或“派生类”。

     

    被继承的类称为“基类”、“父类”或“超类”。

    类的继承:单继承和多继承

     

    继承的过程,就是从一般到特殊的过程。

    要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

    继承概念的实现方式主要有2类:实现继承、接口继承。

             实现继承是指使用基类的属性和方法而无需额外编码的能力;
             接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法);
    python 两种类:经典类 新式类
    python3 新式类 —— 都默认继承object class Animal(object): == class Animal:
    python2 经典类和新式类 并存
    class Animal: 经典类 —— 继承顺序 个别使用方法
    class Animal(object): 新式类
     
    抽象类仅定义将由子类创建的一般属性和方法。

      开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

    派生属性: 在自己的init方法里 使用父类的init方法————指名道姓调用方法

    例子:

    猫类 抓老鼠
    狗类 看门
    动物 吃 喝 睡

     

    class Cat():
        def eat(self):
            print('eating')
        def drink(self):
            print('drinking')
        def sleep(self):
            print('sleeping')
        def catch_mouse(self):
            print('yeah')
    
    class Dog():
        def eat(self):
            print('eating')
        def drink(self):
            print('drinking')
        def sleep(self):
            print('sleeping')
        def watch_door(self):
            print('wangwangwang')

     

     

    上面都有共同的属性,看起来代码重复较多,故可以建立一个动物类,用继承的手段来创建这两个子类。可以解决代码的重复性。

    class Animal:   # 超类、基类
        def eat(self):
            print('eating')
        def drink(self):
            print('drinking')
        def sleep(self):
            print('sleeping')
    
    class Cat(Animal):  # 派生类、子类
        def catch_mouse(self):
            print('yeah')
    
    class Dog(Animal):  # 派生类、子类
        def watch_door(self):
            print('wangwangwang')

    2、继承的分类

      继承一般分为单继承和多继承

    class ParentClass1: #定义父类
        pass
    
    class ParentClass2: #定义父类
        pass
    
    class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
        pass
    
    class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
        pass

    查看继承

    >>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    (<class '__main__.ParentClass1'>,)
    >>> SubClass2.__bases__
    (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

    提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

    >>> ParentClass1.__bases__
    (<class 'object'>,)
    >>> ParentClass2.__bases__
    (<class 'object'>,)

    二、派生

    人 狗 相同属性的同时 还有一些不同的属性
    class Animal:
        def __init__(self,aggressivity, life_value,name):
            self.name = name  # 每一个角色都有自己的昵称;
            self.aggressivity = aggressivity  # 每一个角色都有自己的攻击力;
            self.life_value = life_value  # 每一个角色都有自己的生命值;
        def eat(self):
            self.life_value += 10
    
    class Person(Animal):
        def __init__(self, name, aggressivity, life_value, money):
            Animal.__init__(self, name, aggressivity, life_value)
       # super().__init__(name, aggressivity, life_value) #新式类 self.money
    = money #派生属性:父类没有的属性 def attack(self,dog): dog.life_value -= self.aggressivity def get_weapon(self,weapon_obj): if self.money > weapon_obj.price: self.money -= weapon_obj.price # 金老板花钱买武器 self.weapon = weapon_obj # 金老板装备打狗棒 self.aggressivity += weapon_obj.aggr # 金老板的攻击力增加了 class Dog(Animal): def __init__(self, name, breed, aggressivity, life_value): Animal.__init__(self,aggressivity,life_value,name)
         # super().__init__(name, aggressivity, life_value) #新式类 self.breed
    = breed # 每一只狗都有自己的品种; #派生属性:父类没有的属性 def bite(self,people): # 派生方法 :父类没有的方法 people.life_value -= self.aggressivity def eat(self): Animal.eat(self) print('dog is eating')
    class Animal:
        def __init__(self,name,aggressivity,life_value):
            self.name = name
            self.aggr = aggressivity
            self.life_value = life_value
        def eat(self):
         print('我来了') self.life_value
    += 10 class Person(Animal): def __init__(self,name,aggressivity,life_value,money): super().__init__(name,aggressivity,life_value) # 新式类 self.money = money # 派生属性:父类没有的属性 def attack(self,dog): dog.life_value -= self.aggr class Dog(Animal): def __init__(self,name,aggressivity,life_value,breed): super().__init__(name,aggressivity,life_value) # 新式类 self.breed = breed # 品种,派生属性:父类没有的属性 def bite(self,people): # 派生方法 :父类没有的方法 people.life_value -= self.aggr def eat(self): Animal.eat(self) print('哈哈哈') erha = Dog('小白',10,100,'哈士奇') # 实例化 print(erha.breed) # 查对象的种类 哈士奇 print(erha.name) # 对象的名字 小白 erha.eat() # 哈哈哈 print(erha.life_value) # 110 super(Dog,erha).eat # Animal eat(erha) Animal.eat(erha) # erha 补血 print(erha.life_value) # 120 # 只要想用父类,Animal.eat(snoopy) 父类名.父类的方法(子类对象)

    派生:  父类的基础上又产生了子类—派生类

    派生属性 : 在自己的init方法里 使用父类的init方法 —— 指名道姓调用方法
    派生方法 : 在子类中增加父类没有的
    只要子类有,就有子类的
    只要想用父类,Animal.eat(snoopy) 父类名.父类的方法(子类对象) 2.7经典类中

    用子类的对象,调用父类的方法:
      如果子类中没有这个方法,直接就使用父类的

      如果子类中有同名方法:
        经典类 指名道姓 类名.方法名(子类对象) 类内外一致
        

    新式类 super方法 super(子类名,子类对象).方法名() 类内可以省略super的参数

            super 找父类

    单继承:常用

     多继承:1、钻石继承 

          经典类(深度优先)和新式类(广度优先),mro新式类:查看继承顺序

         2、super

    在多继承中,super不只是寻找当前类的父类,而是依据mro顺序,

    父类子类调用方法的先后顺序
    只要子类有就用子类的,子类没有找父类
    子类父类都想用,先找子类,在子类中调父类(指名道姓,super)

    class D:
        def __init__(self):
            print('d')
    class C(D):
        def __init__(self):
            print('c')
            super().__init__()
    class B(D):
        def __init__(self):
            print('b')
            super().__init__()
    class A(B,C):
        def __init__(self):
            print('a')
            super().__init__()
    #mro
    a = A()
    print(A.mro())
    在多继承中,super不只是寻找当前类的父类,而是依据mro顺序,
    A节点出发,根据广度优先排序查找下一个类

    三、继承的应用(面试题)

    1、对象可以调用自己本类和父类的所有方法和属性, 先调用自己的 自己没有才调父类的。谁(对象)调用方法,方法中的self就指向谁

    class Foo:
        def __init__(self):
            self.func()
    
        def func(self):
            print('Foo.func')
    
    class Son(Foo):
        def func(self):
            print('Son.func')
    
    s = Son()
     # Son.func
    class A:
        def get(self):
            self.say()
    
        def say(self):
            print('AAAAA')
    
    class B(A):
        def say(self):
            print('BBBBB')
    
    b = B()
    b.get()   #输出结果为:BBBBB

     

    四、钻石继承(面试)

    经典类和新式类的多继承问题,继承顺序问题

     

    
    
    深度优先  经典类  py3中
    广度优先 新式类 py2中
     
    class A(object):    #新式类,若不继承object则变成经典类
        def test(self):
            print('from A')
    class B(A):
        def test(self):
            print('from B')
    class C(A):
        def test(self):
            print('from C')
    class D(B):
        def test(self):
            print('from D')
    class E(C):
        def test(self):
            print('from E')
    class F(D,E):
        pass
    f1=F()
    f1.test()
    print(F.__mro__)                       
     #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    
    #新式类继承顺序:F->D->B->E->C->A
    #经典类继承顺序:F->D->B->A->E->C
    #python3中统一都是新式类
    #pyhon2中才分新式类与经典类

     

    一、经典类:

    1、

    2、

    二、新式类(具有查看方法),经典类没有
    1、

    2、

    a = A()
    a.f()
    print(A.mro()) #新式类:查看继承顺序
    在好多个有继承关系的类里面,找一个方法,找的顺序问题
    py3 —— 新式类--广度优先
    py2 —— 经典类--深度优先
    面试 —— 能对应 新式类 是广度优先 经典类是深度优先
    class A:pass
    class B(A):pass
    A、B是经典类
    
    class A1(object):pass
    class B1(A1):pass
    A1、B1是新式类
    钻石继承:新式类为广度优先,经典类为深度优先的原则进行继承,其中在新式类中可以用:子类名.__mro__ 查看继承顺序,而经典类中此方法不存在。

    三、多态特性

      python 天生支持多态

       Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”。

    1、多态

      指的同一事物有多种形态,如动物有:人、狗、猪形态

    import abc
    class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            pass
    
    class People(Animal):                #动物的形态之一:人
        def talk(self):
            print('say hello')
    
    class Dog(Animal):                   #动物的形态之二:狗
        def talk(self):
            print('say wangwang')
    
    class Pig(Animal):                   #动物的形态之三:猪
        def talk(self):
            print('say aoao')

    文件有多种形态:文本文件,可执行文件

    import abc
    class File(metaclass=abc.ABCMeta): #同一类事物:文件
        @abc.abstractmethod
        def click(self):
            pass
    
    class Text(File): #文件的形态之一:文本文件
        def click(self):
            print('open file')
    
    class ExeFile(File): #文件的形态之二:可执行文件
        def click(self):
            print('execute file')

    2、多态性

      多态性是指在不考虑实例类型的情况下使用实例。

    peo=People()
    dog=Dog()
    pig=Pig()
                          #peo、dog、pig都是动物,只要是动物肯定有talk方法
                          #于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
    peo.talk()
    dog.talk()
    pig.talk()
                          #更进一步,我们可以定义一个统一的接口来使用
    def func(obj):
        obj.talk()

    鸭子类型

      :对于某些方法来说,可以无差别对待的几个类型,就是鸭子类型。

    python不崇尚相似数据类型之间的继承关系

      数据类型之间减少依赖关系,解耦

    例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

    例2:序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系

    #二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
    class TxtFile:
        def read(self):
            pass
    
        def write(self):
            pass
    
    class DiskFile:
        def read(self):
            pass
        def write(self):
            pass


  • 相关阅读:
    redis应用场景
    java.lang.IllegalArgumentException: Result Maps collection already contains value for xxx
    Java问题解决:Java compiler level does not match the version of the installed Java project facet.
    win10 安装Oracle 11g release 2
    Oracle 11G Client客户端安装
    Oracle分页查询排序数据重复问题
    Mysql 函数使用记录(三)——UNIX_TIMESTAMP() 、UNIX_TIMESTAMP(date)
    PL/SQL Developer过期解决方法
    PL/SQL Developer登录出现——Using a filter for all users can lead to poor performance!
    Oracle Single-Row Functions(单行函数)——NULL-Related Functions
  • 原文地址:https://www.cnblogs.com/jassin-du/p/7867830.html
Copyright © 2011-2022 走看看