2019-03-27-day020-单继承与多继承

时间:2022-09-03 15:22:36

昨日回顾

类的加载顺序

  • 类内部的代码什么时候执行?
    • 除了方法里面的代码
    • 其余的所有内容都是在执行这个文件的时候就从上到下依次执行的
    • 不需要调用
    • 如果有同名的方法、属性,总是写在后面的会生
class A:
    wahaha = 'adGa'
    def wahaha(self):
        pass
a = A()
print(a.wahaha)   # 就是后加载进来的方法覆盖了之前加载的属性

类和对象的命名空间

  • 类的命名空间 是在定义类的阶段被加载进来的:
    • 静态变量、类变量 —— 直接定义在类中的变量
    • 动态变量、方法 —— 定义在类中的函数
    • 魔术方法、双下方法
      • 内置的方法 :__init__
      • 内置的变量 : __dict__
  • 对象的命名空间 实例化的时候创建出来的
    • 类指针、类对象指针 执行init之前就已经在了
    • 对象的属性 是在执行init以及之后被添加的
class Student:
    '''这里是对学生类的功能描述'''
    print('123')
print(Student.__dict__)
print(Student.__doc__)
print(Student.__class__)

a = 3
b = 2
def fun():
    a = 4
    def inner():pass

class A:
    a = 1
    def func(self):
        pass

print(a)
print(A.a)

class A:  # parameters形参   arguments实参
    pass
a = A()
#init这个东西你在定义一个类的时候
#假如没有什么属性是你想添加给对象的,你也可以不写init
  • 组合
    • 一个类的对象作为另一个类对象的属性
  • 两个类
    • 人和武器
    • 学生和课程
    • 圆环和圆
class Student:
   def __init__(self,name,age,course):
       self.name = name
       self.age = age
       self.course = course   # self.course = python

class Course:
   def __init__(self,name,price,period):
       self.name = name
       self.price = price
       self.period = period

python = Course('python',20000,'6 months')  # python是一个课程对象
print(python.name)
ju = Student('菊哥',30,python)
#一个类的属性 是一个对象
Student类的course属性 是python对象
#学生的课程属性 和 python对象组合了
#可以通过学生 找到python 可以通过python找到python课程的名字、价格、周期

self.course = python
self.course.name = python.name

print(ju.course.name)
print(ju.course.price)

扩展

ju.name   # 字符串
ju.name.strip()
ju是Student类的对象
ju.name是一个字符串 是str的一个对象
Student类 和 str类 组合

ju.age
ju是Student类的对象
ju.age是int的一个对象
Student类 和 int类 组合

今日内容

  • 面向对象三大特性
    1. 继承 *****
    2. 多态 *
    3. 封装 *****
  • 继承 *****
    • 单继承 可以有效的帮我们提高代码的重用性
      1. 我们写代码的时候
    • 多继承
      1. 规范复杂的功能与功能之间的关系
      2. 工作原理能够帮助你去看源码
      3. 面试重点

单继承

class A(类的名字B):
    pass

##A就变成了B的儿子
# B是 父类、基类、超类
# A是 子类、派生类

class Parent:
    pass

class Son(Parent):
    pass

print(Son.__bases__)

##多继承
class Parent1:
    pass
class Parent2:
    pass

class Son(Parent1,Parent2):
    pass

print(Son.__bases__)

为什么要继承

  • 两个类
    1. 猫 :
      • 属性 :名字,品种,眼睛的颜色
      • 动作 :吃、喝、爬树、抓老鼠
      • 属性:名字,品种
      • 动作 :吃、喝、抓老鼠、拆家
class Cat(object):
    def __init__(self,name,kind,eyes_color):
        self.name = name
        self.kind = kind
        self.eyes_color = eyes_color

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

    def drink(self):
        print('%s drink water'%(self.name))

    def climb(self):
        print('%s climb tree'%(self.name))

    def catch(self):
        print('%s catch mouse'%(self.name))

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

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

    def drink(self):
        print('%s drink water'%(self.name))

    def catch(self):
        print('%s catch mouse'%(self.name))

    def chai(self):
        print('%s cha'%(self.name))

class Animal(object):
    def __init__(self,name,kind):
        self.name = name
        self.kind = kind

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

class Cat(Animal):pass
class Dog(Animal):pass

hua = Cat('小花','橘猫')
print(hua)
print(hua.name)
print(hua.kind)
hua.eat('小鱼干')

hei = Dog('小黑','中华田园犬')
print(hei.name)
print(hei.kind)
hei.eat('单身狗粮')

class Animal(object):
    def __init__(self,name,kind):
        self.name = name
        self.kind = kind

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

class Cat(Animal):
    def __init__(self,name,kind,eyes_color):
        self.eyes_color = eyes_color
        Animal.__init__(self,name,kind)   # 在子类和父类有同名方法的时候,默认只执行子类的方法
        # 如果想要执行父类的方法,可以在子类的方法中再 指名道姓 的调用父类的方法

class Dog(Animal):pass

hua = Cat('小花','橘猫','蓝色')
print(hua.__dict__)
当Cat自己拥有__init__的时候,就不再调用父类的了

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

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

class Cat(Animal):
    def __init__(self,name,kind,eyes_color):
        self.eyes_color = eyes_color
        # super(Cat,self).__init__(name,kind)
        # super().__init__(name,kind)   # 相当于执行父类的init方法
        # Animal.__init(self,name,kind)

class Dog(Animal):pass

hua = Cat('小花','橘猫','蓝色')
print(hua.__dict__)

class Animal(object):
    def __init__(self,name,kind):
        self.name = name
        self.kind = kind

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

    def drink(self):
        print('%s drink water'%(self.name))

    def catch(self):
        print('%s catch mouse'%(self.name))

class Cat(Animal):
    def __init__(self,name,kind,eyes_color):
        self.eyes_color = eyes_color  # 派生属性
        # super(Cat,self).__init__(name,kind)
        super().__init__(name,kind)   # 相当于执行父类的init方法
        # Animal.__init(self,name,kind)

    def climb(self):              # 派生方法
        print('%s climb tree'%self.name)

class Dog(Animal):
    def chai(self):
        print('%s cha'%(self.name))

hua = Cat('小花','橘猫','蓝色')
hua.eat('小鱼干')
hua.climb()

子类 父类

子类的对象

想要使用某一个名字

  1. 如果自己有 就用自己的
  2. 如果自己没有 就用父类的
  3. 如果父类也没有 就报错
    ####如果想要使用的名字父类子类都有
  4. 既想使用子类的,也想使用父类的,那就在子类的方法中使用
    1. 父类名.方法名(self,参数1,参数2)
    2. super().方法名(参数1,参数2)
class A:pass
class A(object):pass
print(A.__bases__)
object类
object类是A的父类
#在python3当中,所有的类都继承object类,所有的类都是新式类
#所有的类的类祖宗 都是object
#父类是object的类 —— 新式类

class A(object):
    pass

a = A()   # 总是要调用init的,如果我们不写,实际上就调用父类object的__init__方法了

人狗大战

class Animal(object):
   def __init__(self,name,blood,ad):
       self.name = name
       self.hp = blood
       self.ad = ad
class Dog(Animal):
   def __init__(self,name,blood,ad,kind):
       super().__init__(name,blood,ad)
       self.kind = kind

   def bite(self,person):
       person.hp -= self.ad
       print('%s攻击了%s,%s掉了%s点血' % (self.name, person.name, person.name, self.ad))

class Person(Animal):
   def __init__(self,name,hp,ad,sex):
       super().__init__(name,hp,ad)
       self.sex = sex

   def fight(self,dog):
       dog.hp -= self.ad
       print('%s攻击了%s,%s掉了%s点血'%(self.name,dog.name,dog.name,self.ad))

hei = Dog('小黑',300,20,'哈士奇')
alex = Person('alex',20,1,'不详')
alex.fight(hei)
print(hei.hp)
hei.bite(alex)
print(alex.hp)

抽象

继承

  • 组合 :什么有什么
  • 继承 :什么是什么的关系
    1. 先想描述的对象
    2. 先写出对象所对应的类
    3. 发现多个类之间有相同的代码
    4. 把相同的代码提取出来,搞成一个父类

先抽象,再继承

对象 -->类 -->基类

基类 -继承-> 子类 -实例化-> 对象

多继承

各种动物,每一种动物都是一个类

1. 青蛙、天鹅、老虎、鹦鹉
2. 青蛙 :走,游泳
3. 天鹅 :走,游泳,飞
4. 老虎 :走,游泳
5. 鹦鹉 :走,飞,说话
class FlyAnimal:
    def fly(self):pass
class SwimAnimal:
    def swim(self):pass
    def eat():pass
class WalkAnimal:
    def walk(self):pass
    def eat():pass

class Frog(SwimAnimal,WalkAnimal): pass
class Tiger(SwimAnimal,WalkAnimal):pass
class Swan(FlyAnimal,SwimAnimal,WalkAnimal):pass
class Parrot(FlyAnimal,WalkAnimal):
    def talk(self):
        pass
  • 多继承 是python语言中特有的继承方式
  • java语言中不支持多继承的,C#也不支持多继承
  • C++支持多继承

多继承和单继承是一样的

  1. 如果对象使用名字
  2. 是子类中有的,那么一定用子类的
  3. 子类没有,可以到多个父类中去寻找
    ##如果多个和父类都有,那么用谁的

钻石继承问题

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

class B(A):
    pass
    # def func(self):
    #     print('b')

class C(A):
    pass
    # def func(self):
    #     print('c')

class D(B,C):
    pass
    # def func(self):
    #     print('d')

d = D()
d.func()

乌龟继承问题

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

class B(A):
    pass
    # def func(self):
    #     print('b')

class C(A):
    pass
    # def func(self):
    #     print('c')

class D(B):
    pass
    # def func(self):
    #     print('d')

class E(C):
    pass
    # def func(self):
    #     print('e')

class F(D,E):
    pass
    # def func(self):
    #     print('f')
f = F()
f.func()

广度优先

C3算法

99%的情况都可以用眼睛看出来

但是仍然有1%的情况是看不出来的

C3算法是怎么计算的

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

class B(A):
    pass
    def func(self):
        print('b')

class C(A):
    pass
    def func(self):
        print('c')
class F:
    pass
    def func(self):
        print('f')

class D(A,F):
    pass
    # def func(self):
    #     print('d')

class E(B,C,F):
    pass
    def func(self):
        print('e')

class G(C,D):
    pass
    def func(self):
        print('g')

class H(E,G):
    pass
    def func(self):
        print('h')

print(H.mro())   # 就是帮助我们来展示c3算法的继承顺序

C3算法

A= [AO]
B = B ,B节点的父类对应的顺序
B = B ,A节点顺序
B = B ,[AO]
提取第一个点
   # 如果从左到右第一个类,
   # 在后面的继承顺序中也是第一个,或者不再出现在后面的继承顺序中
   # 那么就可以把这个点提取出来,作为继承顺序中的第一个类
B = [AO]
BA = [O]
B这个节点的继承顺序 :[BAO]

C = C,[AO]
C = [AO]
CA = [O]
C这个节点的继承顺序 :[CAO]

l(D) = D + [BAO]
D = [BAO]
[DBAO]

l(E) = E + [CAO]
[ECAO]

L[F] = F,[DBAO],[ECAO]
[F] = [DBAO],[ECAO]
[FD] = [BAO],[ECAO]
[FDB] = [AO],[ECAO]
[FDB] = [AO],[ECAO]
[FDBE] = [AO],[CAO]
[FDBEC] = [AO],[AO]
[FDBECA] = [O],[O]
[FDBECAO]

经典类和新式类

  • py2.7 经典类
  • 2个图
    1. 看 C3 mro
    2. 你自己去网上找一张图
class A(object):
    def func(self):
        print('a')

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

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

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

b = B()
b.func()
#在多继承中,super就只和mro顺序有关系,和父类子类没有关系了

总结

  • python的继承
  • 提高代码的重用性,减少了代码的冗余
  • 单继承
    1. 子类有的就用子类的
    2. 没有的就用父类的
    3. 如果父类子类都想用,super(),父类名.方法名
  • 多继承
    • 新式类 :继承object
      1. py2 要主动继承object才是新式类,默认是经典类
      2. 遵循的是广度优先算法,C3算法
      3. 有super()的,super遵循mro顺序的
      4. 有mro()方法
    • 经典类 :不继承object
      1. 多个类之间去寻找方法的时候遵循深度优先
      2. 没有super方法也没有mro