📜  Python|单继承中的 super()

📅  最后修改于: 2022-05-13 01:54:46.824000             🧑  作者: Mango

Python|单继承中的 super()

先决条件:继承,函数覆盖

在相当抽象的级别上, super()提供了对超类(父类)的那些方法的访问,这些方法已在从它继承的子类(子类)中被覆盖。考虑下面给出的代码示例,这里我们有一个名为Square的类和另一个名为Cube的类,它继承了类Square

class Square:
     def __init__(self, side):
         self.side = side
  
     def area(self):
         return self.side * self.side
  
class Cube(Square):
      def area(self):
         face_area = self.side * self.side
         return face_area * 6
  
     def volume(self):
         face_area = self.side * self.side
         return face_area * self.side

注意:由于Cube class没有__init__()方法,所以Square class__init__()将用于初始化Cube实例(继承的基本属性)。

考虑到这个例子,我们知道立方体的每个面都是正方形,因此立方体的face_area表示正方形的area 。现在,使用类Squarearea()方法评估face_area是有意义的,而不是手动计算它,这不仅可以避免我们重写代码,还可以从一个地方更改area()逻辑。但是由于我们已经覆盖了Cube中的area()方法,我们不能使用self.area()调用Squarearea()方法。
现在,这是super()来救援的情况。 super()返回父类的代理对象,然后您在该代理对象上调用您选择的方法,因此,我们可以使用super()调用Square classarea()方法,如super().area() .下面是class Cube的修改定义。

class Cube(Square):
     def area(self):
         return super().area() * 6
  
     def volume(self):
         return super().area() * self.side()

请注意,我们可以将Square方法的area()称为Square.area()而不是super().area()但后者更容易换出超类或在需要时重命名它,从而使代码更容易维护。super()中传递参数 –
在上一节中,我们讨论了如何在不带任何参数的情况下使用super() ,但这只能让我们访问作为子类的直接父级的超类的方法。

要访问不是子类的直接父类的超类的方法,我们使用带有两个参数的super() 。让我们考虑一个名为SquareSquarePrismCube的三个类的示例,以了解如何将super()与参数一起使用。
现在,立方体只是一种特殊类型的方形棱镜,它的高度等于它的底边,因此立方体与 SquarePrism 的相似性远大于它与 Square 的相似性。因此,在本例中, class Cube将继承class SquarePrismclass
SquarePrism
将继承class Square 。对于Square类,我们将使用上一节中使用的相同定义。下面给出了我们新定义的类SquarePrism的定义。

class SquarePrism(Square):
     def __init__(self, side, height):
         self.side = side
         self.height = height
  
     def face_area(self):
         base_area = super().area()
         lateral_area = self.side * self.height
         return base_area, lateral_area
  
     def area(self):
         base_area = super().area()
         lateral_area = self.side * self.height
         return 2 * base_area + 4 * lateral_area

SquarePrism实例有两个属性,它的方形底边和方形棱镜的高度。实例方法face_area()返回一个由两个数字组成的元组,分别表示方形棱镜的底面积和方形棱镜的侧面面积。由于底面是正方形,对于正方形棱镜的底面积,我们将方法Square.area()称为super().area()area()方法返回方形棱镜的总表面积。

到目前为止,我们使用了不带任何参数的super() ,现在遵循新类Cube的定义,它将演示带参数的super()的使用。

class Cube(SquarePrism):
     def __init__(self, side)
         super().__init__(side = side, height = side)
  
     def face_area(self):
         return super(SquarePrism, self).area()
  
     def area(self):
         return super().area()

__init__()area() ) 方法不同, Cubeface_area()方法与其对应的SquarePrism.face_area() () 方法有些不同。对于一个立方体,侧面积等于底面积,因此, face_area()方法返回元组是没有意义的,因此class Cubeface_area()将返回立方体面之一的面积.
现在,由于立方体的每个面都是正方形,因此使用class Squarearea()方法再次有意义。现在,由于class Square不是class Cube的直接父类,我们不能将class Squarearea()方法作为super().area()访问,因为它将调用方法SquarePrism.area()

这里我们使用super(SquarePrism, self).face_area()来调用class Squarearea()方法。在第一个参数中, SquarePrism表示super()在类SquarePrism,的直接父级中搜索area()方法,即class Square中。使用self作为第二个参数将当前Cube对象的上下文提供给super()以便请求的area()方法对其进行操作。

请记住,要以双参数形式使用super() ,作为第二个参数传递的对象必须是作为第一个参数传递的type的实例。

注意:由于类Cubeclass SquarePrism的子类,因此Cube实例也是class SquarePrismclass Square的实例。

尝试以下代码片段并观察输出以澄清上述观点。

class Square:
    def __init__(self):
        pass
  
class SquarePrism(Square):
    def __init__(self):
        pass
  
class Cube(SquarePrism):
    def __init__(self):
        pass
  
square = Square()
squareprism = SquarePrism()
cube = Cube()
  
print(isinstance(squareprism, Square))
print(isinstance(cube, Square))

值得注意的是, super()的零参数形式只能在类定义中使用,因为它是由编译器使用适当的参数自动填充的,即如果我们在类中使用super() ,比如Xsuper()将被编译器转换为super(X, self)

虽然super()的零参数形式在开发人员中很流行,但两个参数形式目前似乎没有多大用处。但是在多重继承中,两个参数的形式起着非常重要的作用。