类的继承
类的继承
在前面的示例中,我们一直在使用 Student 这个类。现在我们的需求升级了,不但需要在 Student 中加入更多的属性和方法,还需要新增一个 Teacher 类。按照之前的思路,我们可以这么书写:
class Student:
name = ''
age = 0
gender = ''
grade = 1
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hello(self):
print('Hello!')
def introduction(self):
print('Hello, I am student', self.name)
class Teacher:
name = ''
age = 0
gender = ''
subject = ''
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hello(self):
print('Hello!')
def introduction(self):
print('Hello, I am teacher', self.name)我们发现,这两个类有着许多十分相似的地方:name age gender 三个相同的属性,__init__ say_hello 两个相同的方法,以及两个相似的 introduction 方法。
我们考虑定义一个类 Person,它将实现 Student 和 Teacher 共有的部分;随后,在定义 Student 和 Teacher 时,我们引用 Person,即可继承其中定义的属性和方法:
class Person:
name = ''
age = 0
gender = ''
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hello(self):
print('Hello!')
class Student(Person):
grade = 1
def introduction(self):
print('Hello, I am student', self.name)
class Teacher(Person):
subject = ''
def introduction(self):
print('Hello, I am teacher', self.name)将公共部分抽离后代码简短了一些,也变得更加直观了。
我们在类的定义后面跟上一个括号,括号中写上要被继承的类。这一过程便被称为类的继承。Person 被称作 Student 和 Teacher 的父类,而 Student 和 Teacher 分别为 Person 的子类。一个类的子类和父类都可以有多个。
在上面的代码后面执行这段代码,会得到这样的输出:
student = Student('小明', 10, '男')
student.say_hello() # Hello
student.introduction() # Hello, I am student 小明
teacher = Teacher('小红', 20, '女')
teacher.say_hello() # Hello
teacher.introduction() # Hello, I am teacher 小红方法重写
现在要对 Teacher 类的 say_hello 方法进行更改:将输出的内容改为 'Hello students!'。
我们发现,这样一来 Teacher 中的 say_hello 方法和 Student 中不一样了,而继承的部分一定是统一的才行。我们必须要将 Person 中的 say_hello 方法重新放回两个类中去分别定义吗?
假设我们还有 Worker 等等一些其它的、也同时都继承自 Person 的类,这样操作就太麻烦了。我们可以对类的方法进行重写。
运行代码
class Person:
name = ''
age = 0
gender = ''
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hello(self):
print('Hello!')
class Student(Person):
grade = 1
def introduction(self):
print('Hello, I am student', self.name)
class Teacher(Person):
subject = ''
def say_hello(self):
print('Hello students!')
def introduction(self):
print('Hello, I am teacher', self.name)
student = Student('小明', 10, '男')
student.say_hello() # Hello
student.introduction() # Hello, I am student 小明
teacher = Teacher('小红', 20, '女')
teacher.say_hello() # Hello students!
teacher.introduction() # Hello, I am teacher 小红我们在子类 Teahcer 中定义了一个和父类中方法的名字一样的方法,Python 会自动使用子类中的定义而抛弃父类中的定义。
super()
基本用例
一个类可以通过 super() 调用其继承的类的函数:
运行代码
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Student(Person):
def __init__(self, name, age, grade):
self.grade = grade
super().__init__(name, age)高级使用
super() 可以传入两个参数,分别代表从哪个类向后找和传入的 self
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Student(Person):
def __init__(self, name, age, grade):
self.grade = grade
super().__init__(name, age)
# 上面一行语句等价于
super(Student, self).__init__(name, age)比如我们有 Person 继承 Animal,Student 继承 Person,想要在 Student 里调用 Animal 的函数,可以如下使用:
class Animal:
def __init__(self, age):
self.age = age
class Person(Animal):
def __init__(self, name):
self.name = name
class Student(Person):
def __init__(self, name, age, grade):
self.grade = grade
super(Student, self).__init__(name)
super(Person, self).__init__(age)相关信息
上面的例子只是一个掩饰。如果在现实中遇到这样的需求,代码应该这样写:
class Animal:
def __init__(self, age):
self.age = age
class Person(Animal):
def __init__(self, name, age):
self.name = name
super().__init__(age)
class Student(Person):
def __init__(self, name, age, grade):
self.grade = grade
super().__init__(name, age)super的全局使用
除了类的方法内部,在 Python 代码的任意位置都可以调用 super() 函数。只不过,在方法之外的位置使用必须完整传递两个参数:
运行代码
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hello(self):
print('Hello!')
class Teacher(People):
subject = ''
def say_hello(self):
print('Hello students!')
teacher = Teacher('小红', 20, '女')
teacher.say_hello() # Hello students!
super(Teacher, teacher).say_hello() # Hello!从左到右查找
在多重继承中,super() 会遵循从左到右继承原则,即从继承列表的左侧开始查找父类:
运行代码
class A:
def func(self):
print("A")
class B(A):
def func(self):
print("B")
super().func()
class C(A):
def func(self):
print("C")
super().func()
class D(B, C):
def func(self):
print("D")
super().func()
d = D()
d.func()强烈谴责 NYUSH 25Fall ICDS Midterm 出了上面这道题
在上方给出的代码中,当第 7 行被运行时,不会直接调用类 A 的 func 方法,而是会继续调用类 C 的 func 方法:此时 super() 并非对于类 B 而言,而是对于类 D 实例化产生的对象 d 而言的。d 的类是 D,所以 super() 会继续查找 D 的下一个父类 C。
总而言之,super() 会基于对象真正属于的类(此例中为 D)一级一级向上查找父类,如果有多个父类,则会按照继承时的顺序从左到右查找;总是先遍历当前类直接继承的父类,然后再遍历父类的父类。
如果你希望了解更多有关 MRO(Method Resolution Order)的信息,可以参考:
版权所有
版权归属:异想之旅 | YuzhenQin