跳到主要内容

Python 继承

提示
  1. 类继承简化代码:Python允许从现有类创建新类(子类),继承其属性和方法,促进代码重用。
  2. 方法覆盖增加灵活性:子类可以覆盖超类方法,实现定制化功能,同时保持结构的一致性。
  3. super()方法提升可用性:使用super()方法,子类能够访问并扩展超类的功能,增强了代码的可维护性和扩展性。

像其他面向对象编程语言一样,Python也支持类继承的概念。

继承允许我们从现有的类创建一个新类。

创建的新类被称为子类(子类或派生类),而子类派生自的现有类被称为超类(父类或基类)。

Python继承语法

以下是Python中继承的语法,

# 定义一个超类
class super_class:
# 属性和方法定义
# 继承
class sub_class(super_class):
# super_class的属性和方法
# sub_class的属性和方法

这里,我们从super_class类继承了sub_class类。

示例1:Python继承

class Animal:

# 父类的属性和方法
name = ""

def eat(self):
print("我会吃")

# 继承自Animal
class Dog(Animal):

# 子类中的新方法
def display(self):
# 使用self访问超类的name属性
print("我的名字是", self.name)

# 创建一个子类的对象
labrador = Dog()

# 访问超类的属性和方法
labrador.name = "Rohu"
labrador.eat()

# 调用子类方法
labrador.display()

输出

我会吃
我的名字是Rohu

在上面的示例中,我们从超类Animal派生了一个子类Dog。注意这些语句,

labrador.name = "Rohu"

labrador.eat()

这里,我们使用labrador(Dog的对象)来访问Animal类的name和eat()。这是因为子类继承了超类的所有属性和方法。

此外,我们在Dog类的方法内部使用self访问了name属性。

is-a关系

在Python中,继承是一个is-a关系。也就是说,我们只有在两个类之间存在is-a关系时才使用继承。例如,

  1. Car是一个Vehicle
  2. Apple是一个Fruit
  3. Cat是一个Animal

这里,Car可以从Vehicle继承,Apple可以从Fruit继承,等等。

示例2:Python中的继承

让我们看看Python中继承的另一个例子,

多边形是一个具有3个或更多边的封闭图形。假设我们有一个名为Polygon的类,定义如下,

class Polygon:
def __init__(self, no_of_sides):
self.n = no_of_sides
self.sides = [0 for i in range(no_of_sides)]

def inputSides(self):
self.sides = [float(input("输入边"+str(i+1)+"的长度:")) for i in range(self.n)]

def dispSides(self):
for i in range(self.n):
print("边",i+1,"的长度是",self.sides[i])

这个类有数据属性来存储边的数量n和作为一个列表称为sides的每边的大小。

  • inputSides()方法接收每边的长度
  • dispSides()方法显示这些边的长度

三角形是具有3边的多边形。所以,我们可以创建一个从Polygon继承的名为Triangle的类。这使得Polygon类的所有属性都可用于Triangle类。

我们不需要再次定义它们 (代码复用性)Triangle可以定义如下。

class Triangle(Polygon):
def __init__(self):
Polygon.__init__(self,3)

def findArea(self):
a, b, c = self.sides
# 计算半周长
s = (a + b + c) / 2
# 使用海伦公式计算三角形的面积
area = (s*(s-a)*(s-b)*(s-c)) ** 0.5
print('三角形的面积是 %0.2f' %area)

然而,Triangle类有一个新方法findArea()来找出并打印三角形的面积。

现在让我们看看上面的完整工作代码,包括创建一个对象,

class Polygon:
# 初始化边的数量
def __init__(self, no_of_sides):
self.n = no_of_sides
self.sides = [0 for i in range(no_of_sides)]

def inputSides(self):
self.sides = [float(input("输入边"+str(i+1)+"的长度:")) for i in range(self.n)]

# 显示多边形每边的长度的方法
def dispSides(self):
for i in range(self.n):
print("边",i+1,"的长度是",self.sides[i])

class Triangle(Polygon):
# 通过调用Polygon类的__init__方法,初始化三角形的边数为3
def __init__(self):
Polygon.__init__(self,3)

def findArea(self):
a, b, c = self.sides

# 计算半周长
s = (a + b + c) / 2

# 使用海伦公式计算三角形的面积
area = (s*(s-a)*(s-b)*(s-c)) ** 0.5
print('三角形的面积是 %0.2f' %area)

# 创建Triangle类的实例
t = Triangle()

# 提示用户输入三角形的边
t.inputSides()

# 显示三角形的边
t.dispSides()

# 计算并打印三角形的面积
t.findArea()

输出

输入边1的长度:3
输入边2的长度:5
输入边3的长度:4
1的长度是3.0
2的长度是5.0
3的长度是4.0
三角形的面积是6.00

在这里,我们可以看到,即使我们没有为Triangle类单独定义inputSides()dispSides()方法,我们仍然可以使用它们。

如果在类本身中找不到属性,则搜索将继续到基类。如果基类本身来自其他类,这将递归重复。

Python继承中的方法覆盖

在前面的示例中,我们看到子类的对象可以访问超类的方法。

然而,如果超类和子类中都存在相同的方法呢?

在这种情况下,子类中的方法会覆盖超类中的方法。这种概念被称为Python中的方法覆盖。

示例:方法覆盖

class Animal:

# 父类的属性和方法
name = ""

def eat(self):
print("我会吃")

# 继承自Animal
class Dog(Animal):

# 覆盖eat()方法
def eat(self):
print("我喜欢吃骨头")

# 创建一个子类的对象
labrador = Dog()

# 调用labrador对象的eat()方法
labrador.eat()

输出

我喜欢吃骨头

在上面的示例中,Dog类和Animal类中都存在相同的方法eat()

现在,当我们使用Dog子类的对象调用eat()方法时,将调用Dog类的方法。

这是因为Dog子类中的eat()方法覆盖了Animal超类中的同名方法。

Python继承中的super()方法

之前我们看到,子类中的相同方法会覆盖超类中的方法。

然而,如果我们需要从子类中访问超类的方法,我们使用super()方法。例如,

class Animal:
name = ""
def eat(self):
print("我会吃")

# 继承自Animal
class Dog(Animal):
# 覆盖eat()方法
def eat(self):
# 使用super()调用超类的eat()方法
super().eat()
print("我喜欢吃骨头")

# 创建一个子类的对象
labrador = Dog()

labrador.eat()

输出

我会吃
我喜欢吃骨头

在上面的示例中,Dog子类的eat()方法覆盖了Animal超类的同名方法。

在Dog类内部,我们使用了

# 调用超类的方法
super().eat()

来从Dog子类调用Animal超类的eat()方法。

因此,当我们使用labrador对象调用eat()方法时

# 调用eat()方法
labrador.eat()

覆盖的方法和超类版本的eat()方法都被执行了。

继承的用途

  1. 由于子类可以继承父类的所有功能,这允许代码复用。
  2. 一旦一个功能开发出来,你就可以简单地继承它。无需重新发明轮子。这使得代码更干净,更易于维护。
  3. 由于你还可以在子类中添加自己的功能,你可以只继承有用的功能,并定义其他所需的特性。