1. 引言
许多同学在开始学习Python中的面向对象编程时,对于子类的构造函数的初始化操作,经常会感到些许困惑,这里我来试图让它不那么令人困扰。
闲话少说,我们直接开始吧!
2. 准备工作
在面向对象编程中,为了实现多态,他们经常需要使用继承的思想。对于父类和子类,我们必须非常清楚__init___()
函数的作用。
本文重点考虑一下三种情况:
首先是父类和子类参数量相同的情况,如下:
# parent & child takes in the SAME number of args# Animal(name, age) # parent class
# Dog(name, age) # child class
接着是子类参数量多于父类的情况,如下:
# child takes in MORE args than parent# Employee(name, age) # parent class
# Executive(name, age, rank) # child class
最后是子类参数量少于父类的情形,如下:
# child takes in FEWER args than parent# Rectangle(length, width) # parent class
# Square(length) # child class
3. 情形一:子类父类参数量一致
我们对上述父类Animal(name, age)
和 子类Dog(name, age)
, 进行简单定义实现。
首先是父类Amimal
:
# parent class
class Animal:def __init__(self, name, age):self.name = nameself.age = age
接着是子类Dog
:
# child class
class Dog(Animal):# Dog's __init__ should follow Dog(name, age)def __init__(self, name, age):# super().__init__ here refers to Animal.__init__super().__init__(name, age)
由于我们的子类Dog
继承自父类Animal
, 所以当我们运行子类Dog
中的__init__
函数时:
super()
指的是Dog
的父类Amimal
super().__init__()
指的是父类Animal
中的__init__
函数- 当
super().__init__()
运行时,实质上是Animal
中__init__
函数在运行,即执行语句self.name=name
以及self.age=age
由于父类Animal
和子类Dog
的初始化参数都是(name,age)
, 所以我们不需要修改子类Dog
的__init__
函数,我们只需要在子类Dog
中简单地使用父类的__init__
方法即可。
4. 情形二:子类参数量比父类参数量多
我们对上述父类Employee(name, age)
和 子类Executive(name, age, rank)
, 进行简单定义实现。
首先是父类Employee
:
# parent class
class Employee:def __init__(self, name, age):self.name = nameself.age = age
接着是子类Executive
的定义:
# child class
class Executive(Employee):# Executive.__init__ follows Executive(name, age, rank)def __init__(self, name, age, rank):# super().__init__ refers to Employee.__init__# super().__init__ should follow Employee(name, age)super().__init__(name, age)# super().__init__() does not set rank, so we must do it manuallyself.rank = rank
同上,当我们在子类Executive
调用super().__init__()
时,我们实质上运行的是父类Employee
中的self.name = name
和self.age = age
。同时由于父类Employee
中并没有初始化参数rank
, 因此我们需要在子类Executive
中手动指定改参数的初始化。
简而言之,我们在子类Executive
中调用 super().__init__(name, age)
和 self.rank = rank
,实质上等价于执行如下语句self.name = name
,self.age = age
以及self.rank = rank
.
5. 情形三:子类参数量比父类参数量少
我们对上述父类Rectangle(length, width)
和 子类Square(length)
, 进行简单定义实现。
首先是父类Rectangle
的定义:
# parent class
class Rectangle:def __init__(self, length, width):self.length = lengthself.width = width
接着是子类Square
的定义:
# chid class
class Square(Rectangle):# Square.__init__ should follow Square(length)def __init__(self, length):# super().__init__ should follow Rectangle()super().__init__(length, length)
我们知道,在子类正方形中默认length=width
,所以我们对该类的__init__
函数只需要传入一个参数length
即可。同样的当我们在子类Square
中调用super().__init()
函数时,我们调用的是父类Rectangle
中的__init__
函数。
通过将参数length
传递给子类,并调用父类的初始化函数,实质上(length,length)
通过Square
传递时,实质上等效于self.length = length
和self.width = length
,这和我们的常识正方形中长度和宽度相等是保持一致的。
6. 总结
本文重点介绍了使用Python进行面向对象编程时,父类和子类初始化函数构造时的三种情形下的差异点,可以帮助大家更加深入的理解多态的实现。
嗯嗯,您学废了嘛?