面对对象三大特征:继承 多态(鸭子类型)(面试题)

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

组合:什么有什么的关系

父类:基类或超类

 

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

 

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

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

 

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

要实现继承,可以通过“继承”(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


原文地址:https://www.cnblogs.com/jassin-du/p/7867830.html