面向对象之继承

一、组合

1、定义:自定义类的对象作为类的属性

A类的对象具备某一个属性,该属性的值是B类的对象
基于这种方式就把A类与B类组合到一起
对象既能使用A类中的数据与功能,也能使用B类中的数据与功能

2、作用:组合与继承的作用一样,都是用来减少类与类之间的重复代码

class Teacher:
    def __init__(self, name, age):
        self.name = name
        self.age = age

t1 = Teacher('Owen', 17)
print(t1.name, t1.age)               # Owen 17
print(type(t1.name), type(t1.age))   # <class 'str'> <class 'int'>

class Student:
    # 学生可以有老师属性
    def __init__(self, name, age, teacher):
        self.name = name
        self.age = age

        # 自定义类的对象作为类的属性
        self.teacher = teacher

stu = Student('Bob',18,t1 )
# print(stu.__dict__)
# {'name': 'Bob', 'age': 18, 'teacher': <__main__.Teacher object at 0x00000000021F7E10>}


# 学生的年龄和姓名
print(stu.name, stu.age)   # Bob 18
# 学生的老师年龄和姓名
print(stu.teacher.name, stu.teacher.age)  # Owen 17

二、继承

1、定义:一种关系,子类可以通过父类获取属性和方法          

继承是一种新建类的方式,新建的类称为子类或派生类          

父类又称为基类、超类    

作用:子类可以“遗传”父类的属性,从而可以减少代码冗余 

如何寻找继承关系:先抽象,再继承,继承描述的就是 一种父子关系/从属关系

2、继承语法:

class Foo1:
         pass

class Bar(Foo1):
         pass

class Bar:     # 在python3中没有继承任何类的类,默认继承object
         pass
例:

class People:
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name + '在吃饭')


class Student(People):
    identify = '学生'
    # def __init__(self, name):
    #     self.name = name

    # def eat(self):
    #     print(self.name + '在吃饭')


student = Student('Bob')
student.eat()         # Bob在吃饭


class Leader(People):
    # def __init__(self, name):
    #     self.name = name
    #
    # def eat(self):
    #     print(self.name + '在吃饭')
    pass


leader = Leader('Yang')
leader.eat()         # Yang在吃饭

3、继承关系(继承规则):继承是类与类之间的关系,寻找这种关系需要先抽象再继承  

①父类的所有未封装的属性和方法,子类都能访问

②父类的所有封装的属性和方法,子类都不能访问 

      在外界通过子类或子类对象,不能访问    

      在子类内部也不能访问

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class OldboyTeacher(OldboyPeople):
    def change_score(self):
        print('teacher %s is changing score' % self.name)

class Oldboystudent(OldboyPeople):
    def choose(self):
        print('student %s choose course' % self.name)

tea1 = OldboyTeacher('egon', 18, 'male')
stu1 = Oldboystudent('alex', 73, 'female')

print(tea1.name, tea1.age, tea1.sex)  # egon 18 male

4、继承关系下的属性查找顺序:

①优先找自身,自身没有找父类

②父类没有找父类的父类

③一直找到最顶级的父类,如果还没有报错

5、抽离和派生

抽离:先有多个共有的类,抽出共性形成父类

派生:子类定义的名字会覆盖父类的同名属性

三、方法重写和重用

1、重写:先写好父类的方法,由于父类方法的功能不满足子类需求

子类可以重写父类方法:方法名与父类相同,自定义方法的实现体

2、重用:还需要父类方法的功能,在父类方法功能基础上再添加新功能

突破点:在子类中去调用父类的方法,还有保证调用者是子类(子类的对象)

# 1、方法的重写
class Sup:
    num = 10
    def test(self):
        print('test sup')

class Sub(Sup):
    num = 100
    # 先写好父类的方法,由于父类方法的功能不满足子类需求,
    # 子类可以重写父类方法:方法名与父类相同,自定义方法的实现体
    def test(self):
        print('test sub')

print(Sub.num)   # 100
Sub().test()     # test sub



# 2、方法的重用
class Sup:
    def test(self):
        print('test sup')

class Sub(Sup):
    pass
    # 重用:还需要父类方法的功能,在父类方法功能基础上再添加新功能
    # 突破点:在子类中去调用父类的方法,还有保证调用者是子类(子类的对象)
    def test(self):
        # python2中写法:super(Sub, self).test()
        # python3中简化写法
        super().test()
        print('test sub')

Sub().test()    # test sub

四、init结合super()

super关键字 

super()可以得到调用父级功能的对象,调用者还是子类对象 

super()只能在子类的方法中使用

uper()本质super(子类类名,当前对象)

# 人类:只需要初始化 - name
# 老师: 要初始化 - name salary
# 学生: 要初始化 - name grade

class Sup:
    def test(self):
        print(self)

    def __init__(self, name):
        self.name = name

class Sub(Sup):
    # 有继承关系下,只要名字相同,即使产生不同,还是属于同一个方法
    def test(self, num):
        super().test()
        print(num)

    # 默认父级的__init__可以被继承过来,
    # 但是会出现子类对象的属性比父类多

    def __init__(self, name, salary):
        super().__init__(name)  # 父级有的共性功能通过super()交给父级做
        self.salary = salary  # 子类特有的自己来完成

# Sub().test(10)
# Sub().test()  # 使用还是使用自身带参的,不能使用父级不带参的
# (本质名字相同就是一个,优先查找自己的)

五、多继承

1、简单的多继承

属性的查找顺序:优先找自己的,如果没有,按照继承先后查找父级

class A:
    name = 'A'
    num = 10

class B:
    name = 'B'
    count = 100

# 子类可以继承所有父类的所有可继承属性
class C(A, B):  # 自己 => A => B

    pass

print(C.num)      # 10
print(C.count)    # 100
print(C.name)     # A
# 打印属性查找的顺序
print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

2、复杂的多继承

class A:
    name = "A"
class B(A):
    name = "B"
class C:
    name = "C"
class D(C):
    name = "D"
class E(B, D):
    name = "E"
print(E.mro())
# [<class '__main__.E'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.D'>, <class '__main__.C'>, <class 'object'>]
 

3、新式类与经典类

①新式类:继承object的类及其子类都是新式类

在python3中如果一类没有继承任何父类,那么默认继承object类,即在python3中所有的类都是新式类 

②经典类:(只在python2中才有)没有继承object的类及其子类都是经典类 

③二者的区分:在菱形继承下

经典类:深度优先查找

新式类:广度优先查找

class Foo(object):
    pass

class Bar(Foo):
    pass

print(Foo.__bases__)  # (<class 'object'>,)
print(Bar.__bases__)  # (<class '__main__.Foo'>,)
原文地址:https://www.cnblogs.com/zhangguosheng1121/p/10742383.html