目录

1 继承的概念

2 继承的写法

3 子类继承父类的属性和方法

4 子类新增父类没有的属性和方法

5 子类重写父类的属性和方法

6 super超类的使用

7 多继承


1 继承的概念

继承是类与类之间的一种关系,子类继承父类。通过继承可以使得子类能够拥有父类的属性和方法,以达到复用的目的。

  • 子类:需要继承的类

  • 父类:被继承的类

父类与子类示意图:

【测试开发学习历程】python类的继承-LMLPHP

理解:

  1. 动物类作为狗的父类,所以狗继承了动物类的属性和方法,比如动物具有吃、跑、睡等特征,狗也同样具备这些特征;

  2. 父类和子类的关系是相对的,子类又可以是它的子类的父类,比如:动物类是狗、猫、牛的父类,狗、猫、牛是子类;但狗又是牧羊犬、中华田园犬的父类,牧羊犬、中华田园犬是子类。

继承的特点:

  1. 父类拥有的属性和方法,则子类一定有(私有的属性和方法可以通过子类对象._父类__方法间接调用),子类的对象可以直接调用父类的属性和方法;

  2. 父类拥有的属性和方法,子类可以修改,这就是重写父类的方法;

  3. 父类没有的属性和方法,子类可以新增。

2 继承的写法

在声明一个类的时候,如果这个类继承了父类,在类名后加括号来指定父类的名称。

# 定义一个父类
class People:
    type="高等生物"
    def get_type(self):
        print("父类的self:", self)
        return self.type
    # 私有方法
    def __study(self):
        return "学习软件测试"
    
#定义一个子类,继承父类People
class Students(People):
    def study(self):
        print("子类的self:", self)
        return "在蓉华学习IT技术"
​
# 创建子类对象,调用父类的属性和方法
s1=Students()
print(s1.type)
print(s1.get_type())
print(s1._People__study())
​
# 通过子类对象s1调用子类的study()方法,可以看出打印的self和父类方法中打印的self是同一个对象,也就是s1这个对象
print(s1.study())

3 子类继承父类的属性和方法

# 定义一个父类
class People:
    type="高等生物"
​
    def get_type(self):
        return self.type
#定义一个子类,集成父类People
class Students(People):
    pass
​
#创建Students类的对象
stu1=Students()
#子类对象可以调用父类的属性和方法,因为继承过来了
print(stu1.type)
print(stu1.get_type())

4 子类新增父类没有的属性和方法

# 定义一个父类
class People:
    type="高等生物"
​
    def get_type(self):
        return self.type
#定义一个子类,集成父类People
class Students(People):
    #子类的属性
    type2 ="小学生"   
    #子类的方法
    def get_type2(self):
        return self.type2
​
#创建Students类的对象
stu1=Students()
#子类对象可以调用父类的属性和方法,因为继承过来了
print(stu1.type)
print(stu1.get_type())

5 子类重写父类的属性和方法

重写父类中的方法的原因:父类中的方法不能满足子类的需要,但是子类又想保留这个方法名。

#把适用于自己的父类方法写成自己的方法
# 定义一个父类
class People:
    type="高等生物"
​
    def get_type(self):
        return self.type
#定义一个子类,继承父类People
class Students(People):
    type ="小学生"
    def get_type(self):
        return self.type
​
#创建Students类的对象
stu1=Students()
#子类对象可以调用父类的属性和方法,因为继承过来了
print(stu1.type)
print(stu1.get_type())

6 super超类的使用

在类的继承中,如果重新定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 超类来实现,比如:

class Animal(object):
    def __init__(self, name):
        self.name = name
​
    def greet(self):
        print('Hello, I am %s.' % self.name)
​
​
class Dog(Animal):
    def greet(self):
        # 在Python3中如下两种方式二选一,都可以实现调用父类的方法
        super(Dog, self).greet()
        # super().greet()
        print("汪汪汪...")
​
Dog("小灰").greet()
# 输出:
Hello, I am 小灰.
汪汪汪...

super超类的作用是调用父类的方法,当在子类中调用父类的同名的方法时,需要通过super超类来调用。不同名的方法可以直接通过self来调用。

python3.x中通过super超类调用父类方法有两种写法:

  1. super().父类的方法(参数)

  2. super(子类名称,self).父类的方法(参数)

super超类的一个最常见用法就是在子类中调用父类的构造方法,Python继承情况下写构造方法的3种典型场景:

  1. 如果子类没有显式声明__init__()方法,不管父类有没有显式地声明__init__()方法,都不需要在子类中手动地调用父类的__init__()方法,系统会实现自动调用;

  2. 如果子类显式声明了__init__()方法,但父类没有显式声明__init__()方法,同样不需要在子类中手动地调用父类的__init__()方法,系统会实现自动调用;

  3. 如果子类和父类都显式声明__init__()方法,则必须在子类的__init__()方法中用super手动地调用父类的__init__()方法(调用父类的__init__()方法时不需要传入self参数)。

举例:

#例子1:父类显式地声明了__init__方法,而子类没有显式地声明了__init__方法
#定义一个父类
class People:
    type="高等生物"
    #构造方法
    def __init__(self, name, age):
        # self表示对象本身
        # 定义属性
        self.name = name
        self.age = age
    def get_type(self):
        return self.type
#定义一个子类,集成父类People
class Students(People):
    pass
​
#创建Students类的对象,需要传入父类构造方法需要的参数,当子类没有显式地声明__init__方法的时候,在创建子类对象之前,系统会自动调用父类的__init__方法来完成父类对象的创建
stu1=Students("张三",30)
print(stu1.name)
print(stu1.age)
​
#例子2:父类没有显式地声明__init__方法,而子类显式地声明了__init__方法
# 定义一个父类
class People:
    type="高等生物"
    #构造方法
    # def __init__(self, name, age):
    #     # self表示对象本身
    #     # 定义属性
    #     self.name = name
    #     self.age = age
    def get_type(self):
        return self.type
#定义一个子类,集成父类People
class Students(People):
    def __init__(self, sex, school):
        self.sex=sex
        self.school=school
​
#创建Students类的对象,因为父类没有显式地声明__init__方法,当子类显式地声明__init__方法的时候,在创建子类对象之前,系统会自动调用父类的默认的不带参的__init__方法来完成父类对象的创建
stu1=Students("男","成都职业技术学院")
print(stu1.sex)
print(stu1.school)
​
#例子3:父类和子类都显式地声明了__init__方法
# 定义一个父类
class People:
    type="高等生物"
    #构造方法
    def __init__(self, name, age):
        # self表示对象本身
        # 定义属性
        self.name = name
        self.age = age
    def get_type(self):
        return self.type
#定义一个子类,集成父类People
class Students(People):
    def __init__(self, sex, school, name, age):
        #当父类和子类中都显式地声明了__init__方法时,需要在子类中用super对象来调用父类的__init__         方法,以完成父类对象的创建,这样才能实现子类继承父类。此时子类的__init__方法的形参包括父类        __init__方法的形参
        super().__init__(name, age)
        self.sex=sex
        self.school=school
        
#例子4:
#子类重写了父类的方法,还需要调用父类的方法
#定义一个父类
class People:
    type="高等生物"
​
    def get_type(self,):
        return self.type
#定义一个子类,集成父类People
class Students(People):
    type1 ="小学生"
    def get_type(self):
        return self.type1
    def super_get_type(self): # 重新父类的方法后用作调用父类的方法
        return super().get_type()
#创建Students类的对象
stu1=Students()
#子类重新父类的方法后再调用父类的方法
print(stu1.super_get_type())

7 多继承

多继承:子类可以拥有多个父类,并且具有所有父类的属性和方法。例如:孩子会继承自己父亲和母亲的特性。

多继承示意图:

【测试开发学习历程】python类的继承-LMLPHP

语法:

class 子类(父类1,父类2,...):
    pass

举例:

class A:
    def __init__(self):
        print("初始化A类对象")
​
class B(A):
    def __init__(self):
        # super().__init__()
        super(B, self).__init__()
        print("初始化B类对象")
​
class C(A):
    def __init__(self):
        super(C, self).__init__()
        print("初始化C类对象")
​
class D(B, C):
    def __init__(self):
        super(D, self).__init__()
        print("初始化D类对象")
​
b = B()
# 输出:
初始化A类对象
初始化B类对象
​
d = D()
# 输出:
初始化A类对象
初始化C类对象
初始化B类对象
初始化D类对象

在创建D类的对象时,按正常的理解,程序调用顺序应该是:实例化D以后,通过super调用类B的__init__,然后B再通过super调用类A的__init__,因此程序输出结果应该是a b d,可实际上程序输出结果却是a c b d,这究其原因,就是因为Python中的MRO的问题了。

MRO:就是方法解析顺序(Method Resolution Order),可以通过类调用__mro__方法来查看MRO

print(D.__mro__)
# 输出:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

从以上输出,可以看出,MRO的顺序是:D-->B-->C-->A-->object(object类是所有类的基类,Python解释器在解释执行代码的时候会自动继承object类),所以执行时输出的顺序就是:A C B D。

举例:思考如下代码的输出是多少?

class A:
    def __init__(self):
        self.n = 2
​
    def add(self, m):
        print("A 类中self为:", self)
        self.n += m
​
class B(A):
    def __init__(self):
        super().__init__()
        # super(B, self).__init__()
        self.n = 3
​
    def add(self, m):
        print("B 类中self为:", self)
        super().add(m)
        self.n += 3
​
class C(A):
    def __init__(self):
        super().__init__()
        # super(C, self).__init__()
        self.n = 4
​
    def add(self, m):
        print("C 类中self为:", self)
        super().add(m)
        self.n += 4
​
class D(B, C):
    def __init__(self):
        super().__init__()
        # super(D, self).__init__()
        self.n = 5
​
    def add(self, m):
        print("D 类中self为:", self)
        super().add(m)
        self.n += 5
​
d = D()
d.add(2)
print(d.n)
04-13 07:41