DAY18 面向对象三大特性之继承

继承

  继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类。父类又被称为超类,基类;新建的类称为子类或者派生类。

  在python3.x版本中,所有的类都默认继承object类。

1.继承与重用

  首先,我们来看看一个例子:

# 猫类:吃喝睡,爬树
# 狗类:吃喝睡,看家

#一。通过之前对面向对象的学习,我们可以轻易的定义出这两个类来:
class Cat:
    def __init__(self,name,kind,food):
        self.name = name
        self.kind = kind
        self.food = food

    def eat(self):
        print('%s吃%s'%(self.name,self.food))
    def drink(self):
        print('%s喝水'%self.name)
    def sleep(self):
        print('%s在睡觉'%self.name)
    def climb(self):
        print('%s在爬树'%self.name)

class Dog:
    def __init__(self,name,kind,food):
        self.name = name
        self.kind = kind
        self.food = food

    def eat(self):
        print('%s吃%s'%(self.name,self.food))
    def drink(self):
        print('%s喝水'%self.name)
    def sleep(self):
        print('%s在睡觉'%self.name)
    def look_after_home(self):
        print('%s在看家'%self.name)

  但是再往深入探讨,我们会发现其实编写的猫类和狗类代码中,很多都冗余代码。有什么方式能够把重复的代码提取出来吗?当然有,这时候就可以用到继承的思想,父类中的所有属性和方法都可以被子类使用。

#二。把冗余的代码提出来,抽象出一个宠物类,让猫类和狗类都继承这个宠物类。
class Pet:
    def __init__(self,name,kind,food):
        self.name = name
        self.kind = kind
        self.food = food

    def eat(self):
        print('%s吃%s'%(self.name,self.food))
    def drink(self):
        print('%s喝水'%self.name)
    def sleep(self):
        print('%s在睡觉'%self.name)

class Cat(Pet):
    def climb(self):
        print('%s在爬树'%self.name)


class Dog(Pet):
    def kanjia(self):
        print('%s在看家'%self.name)


tom = Cat('Tom','暹罗猫','猫粮')   #子类使用名字(静态变量和方法),如果在子类中没有,就使用父类的
hei = Dog('小黑','二哈','狗粮')

tom.climb()
hei.kanjia()

2.继承与派生

  子类也可以定义自己特有的属性或者重新这些属性(但并不会影响到父类),一旦定义了自己的属性且与父类同名时,这种属性称为派生属性。子类的对象调用这个属性时,会直接选择子类中的。

class Pet:
    def __init__(self,name,kind,food):
        print('IN PET')
        self.name = name
        self.kind = kind
        self.food = food
    def eat(self):
        print('%s吃%s'%(self.name,self.food))
    def drink(self):
        print('%s喝水'%self.name)
    def sleep(self):
        print('%s在睡觉'%self.name)

class Cat(Pet):
    def __init__(self,name,kind,food,eye_color):
        print('IN CAT')
        self.eye_color = eye_color   #派生属性
        # Pet.__init__(name,kind,food)
        super().__init__(name,kind,food)  #super方法,可以省去self
    def climb(self):
        print('%s在爬树'%self.name)


class Dog(Pet):
    def kanjia(self):
        print('%s在看家'%self.name)


tom = Cat('阿猫','橘猫','猫粮','绿色')
print(tom.eye_color)
# 派生经典考题:
class Foo:
    def __init__(self):
        self.func()
    def func(self):
        print('in tho foo')

class Son(Foo):
    def func(self):
        print('in the son')

s1 = Son()
>>>
in the son

################
当self去调用某个方法的时候,不要看self在哪里,而是要明确self代表的到底是谁。

  派生总结:

  1.当子类中方法要被调用的时候,子类的对象会直接选择子类中的方法。

  2.父类的方法不会被自动执行。

  3.如果我们既要执行子类的方法又要执行父类中的方法,那么需要在子类的方法中调用父类的方法,有以下两种方法:

  (1)父类名.方法名(self,参数...)

  (2)super().方法名(参数...)   #关于super的查找顺序,请继续往下看。

3.抽象类

  抽象类在python中使用的不是特别多,但是在以后的工作中,公司有可能会使用抽象类来制定开发的规则,在以后看源码的过程中,也可能会碰到抽象类的概念。试想一个场景:在今后的多人开发,功能复杂,许多后期拓展功能的项目中,代码的规范变得尤其的重要,而此时,抽象类就能够起到一个很好的模板作用。

  抽象类只是一个模板的规范,基本不会实现什么功能,所以抽象类是不可以被实例化的。

#定义抽象类,需要引入一个模块。

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):       #抽象类必须继承一个叫ABCMeta的类
    @abstractmethod                     #抽象类规定的方法,用abstractmethod装饰器装饰,规定了
    def pay(self):pass                   后面凡是继承该抽象类的子类都必须有一个同名的方法。

class Alipay(Payment):
    def pay(self,money):
        print('使用支付宝支付了%s元'%money)

4.多继承

  在python中允许一个子类是可以继承多个父类的。

class ParentClass1:  #定义父类1
    pass

class ParentClass2:  #定义父类2
    pass

class ChildClass(ParentClass1):   #定义子类(继承父类1) 单继承
    pass

class ChildClass2(ParentClass1,ParentClass2):  #多继承
    pass

  “__base__”:显示子类的一个父类。

  “__bases__”:显示子类的所有父类。

5.新式类与经典类

  python3.x所有的类都是新式类,所有的新式类都有一个默认继承的父类,叫做object类。

  python2.7中经典类和新式类并存。

    class Student:Pass   #经典类

    class Student(object):pass  #新式类

  总结:

  (1)继承了object的类都是新式类。

  (2)在py3中所有的类都是新式类。

  (3)在py2中既有新式类也有经典类。

 

  一.多继承的顺序/新式类和经典类之间的区别?

 (1)钻石继承:广度优先。

  新式类的所有多继承关系寻找方法的顺序--->遵循广度优先。

  mro()--->显示多继承的继承顺序。

  super()--->super方法不是单纯的寻找父类,在多继承中,是遵循mro循序的。

class A:
    def func(self):
        print('A')

class B(A):
    def func(self):
        super().func()
        print('B')

class C(A):
    def func(self):
        super().func()
        print('C')

class D(B,C):
    def func(self):
        super().func()
        print('D')

d = D()
d.func()
print(D.mro())              #新式类遵循广度优先。
>>>
A
C
B
D
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

  

 总结:

  新式类在多继承时,遵循广度优先。

  经典类在多继承时,遵循深度优先。

  

posted @ 2018-08-28 17:15  hehehe1994  阅读(115)  评论(0编辑  收藏  举报