博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python super_使用Python super()增强您的课程
阅读量:2523 次
发布时间:2019-05-11

本文共 28821 字,大约阅读时间需要 96 分钟。

python super

While Python isn’t purely an object-oriented language, it’s flexible enough and powerful enough to allow you to build your applications using the object-oriented paradigm. One of the ways in which Python achieves this is by supporting inheritance, which it does with super().

尽管Python并不是纯粹的面向对象的语言,但是它足够灵活和强大,可以让您使用面向对象的范例来构建应用程序。 Python实现此目标的方法之一是通过支持继承 ,而继承是通过super()

In this tutorial, you’ll learn about the following:

在本教程中,您将了解以下内容:

  • The concept of inheritance in Python
  • Multiple inheritance in Python
  • How the super() function works
  • How the super() function in single inheritance works
  • How the super() function in multiple inheritance works
  • Python中的继承概念
  • Python中的多重继承
  • super()函数如何工作
  • 单继承中的super()函数如何工作
  • 多重继承中的super()函数如何工作

Free Bonus: , a free course for Python developers that shows you the roadmap and the mindset you’ll need to take your Python skills to the next level.

免费奖金: ,这是针对Python开发人员的免费课程,向您展示了将Python技能提升到新水平所需的路线图和心态。

Python的super()函数概述 (An Overview of Python’s super() Function)

If you have experience with object-oriented languages, you may already be familiar with the functionality of super().

如果您具有面向对象语言的经验,那么您可能已经熟悉super()的功能。

If not, don’t fear! While the is fairly technical, at a high level super() gives you access to methods in a superclass from the subclass that inherits from it.

如果没有,不要害怕! 尽管是相当技术性的,但从较高的角度来看, super()使您可以从继承自父类的子类中访问父类中的方法。

super() alone returns a temporary object of the superclass that then allows you to call that superclass’s methods.

super()返回超类的临时对象,然后允许您调用该超类的方法。

Why would you want to do any of this? While the possibilities are limited by your imagination, a common use case is building classes that extend the functionality of previously built classes.

您为什么要这样做? 尽管可能性受到您的想象力的限制,但是一个常见的用例是构建类,以扩展先前构建的类的功能。

Calling the previously built methods with super() saves you from needing to rewrite those methods in your subclass, and allows you to swap out superclasses with minimal code changes.

使用super()调用以前构建的方法可以使您不必重写子类中的这些方法,并且可以用最少的代码更改交换super()类。

单继承中的super() (super() in Single Inheritance)

If you’re unfamiliar with object-oriented programming concepts, inheritance might be an unfamiliar term. Inheritance is a concept in object-oriented programming in which a class derives (or inherits) attributes and behaviors from another class without needing to implement them again.

如果您不熟悉面向对象的编程概念,则继承可能是一个陌生的术语。 继承是面向对象编程中的一个概念,其中一个类从另一个类派生(或继承 )属性和行为,而无需再次实现它们。

For me at least, it’s easier to understand these concepts when looking at code, so let’s write classes describing some shapes:

至少对我来说,在查看代码时更容易理解这些概念,因此让我们编写描述某些形状的类:

class class RectangleRectangle :    :    def def __init____init__ (( selfself , , lengthlength , , widthwidth ):        ):        selfself .. length length = = length        length        selfself .. width width = = width    width    def def areaarea (( selfself ):        ):        return return selfself .. length length * * selfself .. width    width    def def perimeterperimeter (( selfself ):        ):        return return 2 2 * * selfself .. length length + + 2 2 * * selfself .. widthwidthclass class SquareSquare :    :    def def __init____init__ (( selfself , , lengthlength ):        ):        selfself .. length length = = length    length    def def areaarea (( selfself ):        ):        return return selfself .. length length * * selfself .. length    length    def def perimeterperimeter (( selfself ):        ):        return return 4 4 * * selfself .. lengthlength

Here, there are two similar classes: Rectangle and Square.

在这里,有两个类似的类: RectangleSquare

You can use them as below:

您可以如下使用它们:

>>>
>>>
>>>  square = Square ( 4 )>>>  square . area ()16>>>  rectangle = Rectangle ( 2 , 4 )>>>  rectangle . area ()8

In this example, you have two shapes that are related to each other: a square is a special kind of rectangle. The code, however, doesn’t reflect that relationship and thus has code that is essentially repeated.

在此示例中,您有两个相互关联的形状:正方形是一种特殊的矩形。 但是,该代码无法反映这种关系,因此具有实质上重复的代码。

By using inheritance, you can reduce the amount of code you write while simultaneously reflecting the real-world relationship between rectangles and squares:

通过使用继承,您可以减少编写的代码量,同时反映矩形和正方形之间的实际关系:

Here, you’ve used super() to call the __init__() of the Rectangle class, allowing you to use it in the Square class without repeating code. Below, the core functionality remains after making changes:

在这里,您已经使用super()调用Rectangle类的__init__() ,从而使您可以在Square类中使用它,而无需重复代码。 下面,进行更改后,核心功能仍然保留:

>>>
>>> square = Square(4)>>> square.area()16
>>>

In this example, Rectangle is the superclass, and Square is the subclass.

在此的示例Rectangle是超类, Square是子类。

Because the Square and Rectangle .__init__() methods are so similar, you can simply call the superclass’s .__init__() method (Rectangle.__init__()) from that of Square by using super(). This sets the .length and .width attributes even though you just had to supply a single length parameter to the Square constructor.

因为SquareRectangle .__init__()方法是如此相似,所以您可以使用super()Square调用超类的.__init__()方法( Rectangle.__init__() super() 。 即使您只需要向Square构造函数提供单个length参数,也可以设置.length.width属性。

When you run this, even though your Square class doesn’t explicitly implement it, the call to .area() will use the .area() method in the superclass and print 16. The Square class inherited .area() from the Rectangle class.

当您运行此代码时,即使您的Square类没有明确实现它,对.area()的调用也将使用超类中的.area()方法并打印16Square类从Rectangle继承了 .area()

Note: To learn more about inheritance and object-oriented concepts in Python, be sure to check out .

注意:要了解有关Python中的继承和面向对象概念的更多信息,请务必查看 。

super()可以为您做什么? (What Can super() Do for You?)

So what can super() do for you in single inheritance?

那么super()在单继承中可以为您做什么?

Like in other object-oriented languages, it allows you to call methods of the superclass in your subclass. The primary use case of this is to extend the functionality of the inherited method.

像其他面向对象的语言一样,它允许您在子类中调用超类的方法。 这种方法的主要用例是扩展继承方法的功能。

In the example below, you will create a class Cube that inherits from Square and extends the functionality of .area() (inherited from the Rectangle class through Square) to calculate the surface area and volume of a Cube instance:

在下面的示例中,您将创建一个继承自Square Cube类,并扩展.area()的功能(从Rectangle类继承自Square ),以计算Cube实例的表面积和体积:

class class SquareSquare (( RectangleRectangle ):    ):    def def __init____init__ (( selfself , , lengthlength ):        ):        supersuper ()() .. __init____init__ (( lengthlength , , lengthlength ))class class CubeCube (( SquareSquare ):    ):    def def surface_areasurface_area (( selfself ):        ):        face_area face_area = = supersuper ()() .. areaarea ()        ()        return return face_area face_area * * 6    6    def def volumevolume (( selfself ):        ):        face_area face_area = = supersuper ()() .. areaarea ()        ()        return return face_area face_area * * selfself .. lengthlength

Now that you’ve built the classes, let’s look at the surface area and volume of a cube with a side length of 3:

现在,您已经构建了类,让我们看一下边长为3的立方体的表面积和体积:

>>>
>>>
>>>  cube = Cube ( 3 )>>>  cube . surface_area ()54>>>  cube . volume ()27

Caution: Note that in our example above, super() alone won’t make the method calls for you: you have to call the method on the proxy object itself.

注意 :请注意,在上面的示例中,单独的super()不会使您需要调用该方法:您必须在代理对象本身上调用该方法。

Here you have implemented two methods for the Cube class: .surface_area() and .volume(). Both of these calculations rely on calculating the area of a single face, so rather than reimplementing the area calculation, you use super() to extend the area calculation.

在这里,您为Cube类实现了两种方法: .surface_area().volume() 。 这两个计算都依赖于计算单个面的面积,因此,您可以使用super()来扩展面积计算,而不是重新实现面积计算。

Also notice that the Cube class definition does not have an .__init__(). Because Cube inherits from Square and .__init__() doesn’t really do anything differently for Cube than it already does for Square, you can skip defining it, and the .__init__() of the superclass (Square) will be called automatically.

还要注意, Cube类定义没有.__init__() 。 由于CubeSquare继承而来, .__init__()Cube所做的实际上与对Square所做的没什么不同,因此您可以跳过对其的定义,超类( Square )的.__init__() )将被自动调用。

super() returns a delegate object to a parent class, so you call the method you want directly on it: super().area().

super()将委托对象返回给父类,因此您可以直接在其上调用所需的方法: super().area()

Not only does this save us from having to rewrite the area calculations, but it also allows us to change the internal .area() logic in a single location. This is especially in handy when you have a number of subclasses inheriting from one superclass.

这不仅使我们不必重写面积计算,而且还使我们可以在单个位置更改内部.area()逻辑。 当您有许多从一个超类继承的子类时,这特别方便。

super()潜水 (A super() Deep Dive)

Before heading into multiple inheritance, let’s take a quick detour into the mechanics of super().

在进入多重继承之前,让我们快速绕开super()

While the examples above (and below) call super() without any parameters, super() can also take two parameters: the first is the subclass, and the second parameter is an object that is an instance of that subclass.

虽然上面(和下面)的示例在不带任何参数的情况下调用super() ,但是super()也可以采用两个参数:第一个是子类,第二个参数是作为该子类实例的对象。

First, let’s see two examples showing what manipulating the first variable can do, using the classes already shown:

首先,让我们看两个示例,这些示例使用已经显示的类来操纵第一个变量可以做什么:

In Python 3, the super(Square, self) call is equivalent to the parameterless super() call. The first parameter refers to the subclass Square, while the second parameter refers to a Square object which, in this case, is self. You can call super() with other classes as well:

在Python 3中, super(Square, self)调用等效于无参数super()调用。 第一个参数引用Square子类,而第二个参数引用Square对象,在这种情况下为self 。 您也可以在其他类中调用super()

class class CubeCube (( SquareSquare ):    ):    def def surface_areasurface_area (( selfself ):        ):        face_area face_area = = supersuper (( SquareSquare , , selfself )) .. areaarea ()        ()        return return face_area face_area * * 6    6    def def volumevolume (( selfself ):        ):        face_area face_area = = supersuper (( SquareSquare , , selfself )) .. areaarea ()        ()        return return face_area face_area * * selfself .. lengthlength

In this example, you are setting Square as the subclass argument to super(), instead of Cube. This causes super() to start searching for a matching method (in this case, .area()) at one level above Square in the instance hierarchy, in this case Rectangle.

在此示例中,您将Square设置为super()的子类参数,而不是Cube 。 这将导致super()在实例层次结构中,在Square之上的Square上,在此示例Rectangle上的一个级别上开始搜索匹配方法(在这种情况下, .area() )。

In this specific example, the behavior doesn’t change. But imagine that Square also implemented an .area() function that you wanted to make sure Cube did not use. Calling super() in this way allows you to do that.

在此特定示例中,行为不会改变。 但是,假设Square还实现了.area()函数,您想确保不使用Cube 。 以这种方式调用super()可以做到这一点。

Caution: While we are doing a lot of fiddling with the parameters to super() in order to explore how it works under the hood, I’d caution against doing this regularly.

注意:虽然我们为了弄清楚super()的参数做了很多摆弄,但我还是提醒不要定期进行此操作。

The parameterless call to super() is recommended and sufficient for most use cases, and needing to change the search hierarchy regularly could be indicative of a larger design issue.

建议对super()无参数调用,对于大多数用例而言,这是足够的,并且需要定期更改搜索层次结构可能表明存在较大的设计问题。

What about the second parameter? Remember, this is an object that is an instance of the class used as the first parameter. For an example, isinstance(Cube, Square) must return True.

第二个参数呢? 请记住,这是一个对象,它是用作第一个参数的类的实例。 例如, isinstance(Cube, Square)必须返回True

By including an instantiated object, super() returns a bound method: a method that is bound to the object, which gives the method the object’s context such as any instance attributes. If this parameter is not included, the method returned is just a function, unassociated with an object’s context.

通过包含实例化的对象, super()返回一个绑定方法 :绑定到该对象的方法,该方法为该方法提供对象的上下文,例如任何实例属性。 如果不包含此参数,则返回的方法只是一个函数,与对象的上下文无关。

For more information about bound methods, unbound methods, and functions, read the Python documentation .

有关绑定方法,未绑定方法和函数的更多信息,请阅读的Python文档。

Note: Technically, super() doesn’t return a method. It returns a proxy object. This is an object that delegates calls to the correct class methods without making an additional object in order to do so.

注意:从技术上讲, super()不会返回方法。 它返回一个代理对象 。 这是一个将调用委托给正确的类方法的对象,而无需为此创建其他对象。

多重继承中的super() (super() in Multiple Inheritance)

Now that you’ve worked through an overview and some examples of super() and single inheritance, you will be introduced to an overview and some examples that will demonstrate how multiple inheritance works and how super() enables that functionality.

现在,您已经完成了概述以及super()和单一继承的一些示例,将向您介绍概述和一些示例,这些示例将演示多重继承如何工作以及super()如何启用该功能。

多重继承概述 (Multiple Inheritance Overview)

There is another use case in which super() really shines, and this one isn’t as common as the single inheritance scenario. In addition to single inheritance, Python supports multiple inheritance, in which a subclass can inherit from multiple superclasses that don’t necessarily inherit from each other (also known as sibling classes).

在另一种用例中, super()确实令人眼前一亮,而且这种情况不像单继承方案那样普遍。 除了单一继承,Python还支持多重继承,其中子类可以从不一定彼此继承的多个超类继承(也称为同级类 )。

I’m a very visual person, and I find diagrams are incredibly helpful to understand concepts like this. The image below shows a very simple multiple inheritance scenario, where one class inherits from two unrelated (sibling) superclasses:

我是一个非常有远见的人,我发现图表对于理解这样的概念非常有帮助。 下图显示了一个非常简单的多重继承方案,其中一个类从两个不相关的(同级)超类继承:

多重继承的图解示例
A diagrammed example of multiple inheritance (Image: Kyle Stratis)
多重继承的图解示例(图片:Kyle Stratis)

To better illustrate multiple inheritance in action, here is some code for you to try out, showing how you can build a right pyramid (a pyramid with a square base) out of a Triangle and a Square:

为了更好地说明运行中的多重继承,下面是一些代码供您试用,以显示如何从TriangleSquare构建一个正确的金字塔(具有正方形底的金字塔):

Note: The term slant height may be unfamiliar, especially if it’s been a while since you’ve taken a geometry class or worked on any pyramids.

注意:倾斜高度 ”一词可能并不熟悉,尤其是自从上过几何课或研究过任何金字塔以来已经有一段时间了。

The slant height is the height from the center of the base of an object (like a pyramid) up its face to the peak of that object. You can read more about slant heights at .

倾斜高度是从对象(如金字塔)的底部中心到其表面到该对象的峰顶的高度。 您可以在阅读有关倾斜高度的更多信息。

This example declares a Triangle class and a RightPyramid class that inherits from both Square and Triangle.

本示例声明一个Triangle类和一个RightPyramid类,它们从SquareTriangle继承。

You’ll see another .area() method that uses super() just like in single inheritance, with the aim of it reaching the .perimeter() and .area() methods defined all the way up in the Rectangle class.

您将看到另一种使用super() .area()方法,就像在单继承中一样,其目的是达到Rectangle类中一直定义的.perimeter().area()方法。

Note: You may notice that the code above isn’t using any inherited properties from the Triangle class yet. Later examples will fully take advantage of inheritance from both Triangle and Square.

注意:您可能会注意到,上面的代码尚未使用Triangle类的任何继承属性。 后面的示例将充分利用TriangleSquare的继承。

The problem, though, is that both superclasses (Triangle and Square) define a .area(). Take a second and think about what might happen when you call .area() on RightPyramid, and then try calling it like below:

但是,问题在于两个超类( TriangleSquare )都定义了.area() 。 花点时间,想一想当您在RightPyramid上调用.area()时会发生什么,然后尝试像下面这样调用它:

>>>
>> pyramid = RightPyramid(2, 4)>> pyramid.area()Traceback (most recent call last):  File "shapes.py", line 63, in 
print(pyramid.area()) File "shapes.py", line 47, in area base_area = super().area() File "shapes.py", line 38, in area return 0.5 * self.base * self.heightAttributeError: 'RightPyramid' object has no attribute 'height'
>>>

Did you guess that Python will try to call Triangle.area()? This is because of something called the method resolution order.

您是否猜想Python会尝试调用Triangle.area() ? 这是因为有一种称为方法解析顺序方法

Note: How did we notice that Triangle.area() was called and not, as we hoped, Square.area()? If you look at the last line of the traceback (before the AttributeError), you’ll see a reference to a specific line of code:

注意:我们如何注意到Triangle.area()被调用而不是我们希望的Square.area()被调用了? 如果查看回溯的最后一行( AttributeError之前),则会看到对特定代码行的引用:

return return 0.5 0.5 * * selfself .. base base * * selfself .. heightheight

You may recognize this from geometry class as the formula for the area of a triangle. Otherwise, if you’re like me, you might have scrolled up to the Triangle and Rectangle class definitions and seen this same code in Triangle.area().

您可以从几何图形类中将其识别为三角形面积的公式。 否则,如果您像我一样,则可能已经向上滚动到TriangleRectangle类定义,并在Triangle.area()看到了相同的代码。

方法解析顺序 (Method Resolution Order)

The method resolution order (or MRO) tells Python how to search for inherited methods. This comes in handy when you’re using super() because the MRO tells you exactly where Python will look for a method you’re calling with super() and in what order.

方法解析顺序(或MRO )告诉Python如何搜索继承的方法。 当您使用super()时这会派上用场,因为MRO会告诉您Python将在何处查找您要使用super()调用的方法的确切顺序。

Every class has an .__mro__ attribute that allows us to inspect the order, so let’s do that:

每个类都有一个.__mro__属性,该属性使我们可以检查订单,因此我们可以这样做:

>>>
>>>
>>>  RightPyramid . __mro__(
,
,
,
,
)

This tells us that methods will be searched first in Rightpyramid, then in Triangle, then in Square, then Rectangle, and then, if nothing is found, in object, from which all classes originate.

这告诉我们,将首先在Rightpyramid搜索方法,然后在Triangle ,然后在Square搜索,然后在Rectangle ,然后,如果未找到,则在object中搜索所有类的起源。

The problem here is that the interpreter is searching for .area() in Triangle before Square and Rectangle, and upon finding .area() in Triangle, Python calls it instead of the one you want. Because Triangle.area() expects there to be a .height and a .base attribute, Python throws an AttributeError.

这里的问题是,解释器在SquareRectangle之前的Triangle搜索.area() ,并且在Triangle找到.area()时,Python调用了它,而不是您想要的那个。 因为Triangle.area()期望存在.height.base属性,所以Python抛出AttributeError

Luckily, you have some control over how the MRO is constructed. Just by changing the signature of the RightPyramid class, you can search in the order you want, and the methods will resolve correctly:

幸运的是,您可以控制MRO的构造方式。 只需更改RightPyramid类的签名,就可以按所需顺序搜索,这些方法将正确解析:

Notice that RightPyramid initializes partially with the .__init__() from the Square class. This allows .area() to use the .length on the object, as is designed.

注意, RightPyramid使用Square类中的.__init__()进行了部分初始化。 按照设计,这允许.area()在对象上使用.length

Now, you can build a pyramid, inspect the MRO, and calculate the surface area:

现在,您可以构建金字塔,检查MRO并计算表面积:

>>>
>>> pyramid = RightPyramid(2, 4)>>> RightPyramid.__mro__(
,
,
,
,
)>>> pyramid.area()20.0
>>>

You see that the MRO is now what you’d expect, and you can inspect the area of the pyramid as well, thanks to .area() and .perimeter().

您会看到MRO现在已达到您的期望,并且由于.area().perimeter() ,您还可以检查金字塔的区域。

There’s still a problem here, though. For the sake of simplicity, I did a few things wrong in this example: the first, and arguably most importantly, was that I had two separate classes with the same method name and signature.

但是,这里仍然存在问题。 为了简单起见,在此示例中,我做错了一些事情:第一个,并且可以说是最重要的一点是,我有两个单独的类,它们具有相同的方法名称和签名。

This causes issues with method resolution, because the first instance of .area() that is encountered in the MRO list will be called.

这会导致方法解析出现问题,因为将调用MRO列表中遇到的.area()的第一个实例。

When you’re using super() with multiple inheritance, it’s imperative to design your classes to cooperate. Part of this is ensuring that your methods are unique so that they get resolved in the MRO, by making sure method signatures are unique—whether by using method names or method parameters.

当您使用具有多重继承的super()时,必须设计要进行协作的类。 这部分是通过确保方法签名是唯一的(无论使用方法名称还是方法参数)来确保您的方法是唯一的,以便在MRO中对其进行解析。

In this case, to avoid a complete overhaul of your code, you can rename the Triangle class’s .area() method to .tri_area(). This way, the area methods can continue using class properties rather than taking external parameters:

在这种情况下,为避免彻底检查代码,可以将Triangle类的.area()方法重命名为.tri_area() 。 这样,area方法可以继续使用类属性,而不是采用外部参数:

class class TriangleTriangle :    :    def def __init____init__ (( selfself , , basebase , , heightheight ):        ):        selfself .. base base = = base        base        selfself .. height height = = height        height        supersuper ()() .. __init____init__ ()    ()    def def tri_areatri_area (( selfself ):        ):        return return 0.5 0.5 * * selfself .. base base * * selfself .. heightheight

Let’s also go ahead and use this in the RightPyramid class:

让我们继续在RightPyramid类中使用它:

The next issue here is that the code doesn’t have a delegated Triangle object like it does for a Square object, so calling .area_2() will give us an AttributeError since .base and .height don’t have any values.

这里的下一个问题是代码没有像Square对象那样的委托Triangle对象,因此调用.area_2()会给我们一个AttributeError因为.base.height没有任何值。

You need to do two things to fix this:

您需要做两件事来解决此问题:

  1. All methods that are called with super() need to have a call to their superclass’s version of that method. This means that you will need to add super().__init__() to the .__init__() methods of Triangle and Rectangle.

  2. Redesign all the .__init__() calls to take a keyword dictionary. See the complete code below.

  1. super()调用的所有方法都需要对其方法的超类版本进行调用。 这意味着您需要将super().__init__()TriangleRectangle.__init__()方法中。

  2. 重新设计所有.__init__()调用以采用关键字字典。 请参阅下面的完整代码。

class class RectangleRectangle :    :    def def __init____init__ (( selfself , , lengthlength , , widthwidth , , **** kwargskwargs ):        ):        selfself .. length length = = length        length        selfself .. width width = = width        width        supersuper ()() .. __init____init__ (( **** kwargskwargs )    )    def def areaarea (( selfself ):        ):        return return selfself .. length length * * selfself .. width    width    def def perimeterperimeter (( selfself ):        ):        return return 2 2 * * selfself .. length length + + 2 2 * * selfself .. widthwidth# Here we declare that the Square class inherits from # Here we declare that the Square class inherits from # the Rectangle class# the Rectangle classclass class SquareSquare (( RectangleRectangle ):    ):    def def __init____init__ (( selfself , , lengthlength , , **** kwargskwargs ):        ):        supersuper ()() .. __init____init__ (( lengthlength == lengthlength , , widthwidth == lengthlength , , **** kwargskwargs ))class class CubeCube (( SquareSquare ):    ):    def def surface_areasurface_area (( selfself ):        ):        face_area face_area = = supersuper ()() .. areaarea ()        ()        return return face_area face_area * * 6    6    def def volumevolume (( selfself ):        ):        face_area face_area = = supersuper ()() .. areaarea ()        ()        return return face_area face_area ** ** 33class class TriangleTriangle :    :    def def __init____init__ (( selfself , , basebase , , heightheight , , **** kwargskwargs ):        ):        selfself .. base base = = base        base        selfself .. height height = = height        height        supersuper ()() .. __init____init__ (( **** kwargskwargs )    )    def def tri_areatri_area (( selfself ):        ):        return return 0.5 0.5 * * selfself .. base base * * selfself .. heightheightclass class RightPyramidRightPyramid (( SquareSquare , , TriangleTriangle ):    ):    def def __init____init__ (( selfself , , basebase , , slant_heightslant_height , , **** kwargskwargs ):        ):        selfself .. base base = = base        base        selfself .. slant_height slant_height = = slant_height        slant_height        kwargskwargs [[ "height""height" ] ] = = slant_height        slant_height        kwargskwargs [[ "length""length" ] ] = = base        base        supersuper ()() .. __init____init__ (( basebase == basebase , , **** kwargskwargs )    )    def def areaarea (( selfself ):        ):        base_area base_area = = supersuper ()() .. areaarea ()        ()        perimeter perimeter = = supersuper ()() .. perimeterperimeter ()        ()        return return 0.5 0.5 * * perimeter perimeter * * selfself .. slant_height slant_height + + base_area    base_area    def def area_2area_2 (( selfself ):        ):        base_area base_area = = supersuper ()() .. areaarea ()        ()        triangle_area triangle_area = = supersuper ()() .. tri_areatri_area ()        ()        return return triangle_area triangle_area * * 4 4 + + base_areabase_area

There are a number of important differences in this code:

这段代码有许多重要的区别:

  • kwargs is modified in some places (such as RightPyramid.__init__()): This will allow users of these objects to instantiate them only with the arguments that make sense for that particular object.

  • Setting up named arguments before **kwargs: You can see this in RightPyramid.__init__(). This has the neat effect of popping that key right out of the **kwargs dictionary, so that by the time that it ends up at the end of the MRO in the object class, **kwargs is empty.

  • 在某些地方对kwargs进行了修改(例如RightPyramid.__init__() ):这将允许这些对象的用户仅使用对特定对象有意义的参数来实例化它们。

  • **kwargs之前设置命名参数:您可以在RightPyramid.__init__()看到它。 这具有将键从**kwargs字典中弹出的巧妙效果,因此,当它在object类中的MRO末尾结束时, **kwargs为空。

Note: Following the state of kwargs can be tricky here, so here’s a table of .__init__() calls in order, showing the class that owns that call, and the contents of kwargs during that call:

注意:在此处跟踪kwargs的状态可能很棘手,因此按顺序列出了.__init__()调用的表,显示了拥有该调用的类以及该调用期间kwargs的内容:

Class Named Arguments 命名参数 kwargskwargs
RightPyramidRightPyramid base, base slant_heightslant_height
SquareSquare lengthlength base, base heightheight
RectangleRectangle length, lengthwidthwidth base, base heightheight
TriangleTriangle base, base heightheight

Now, when you use these updated classes, you have this:

现在,当您使用这些更新的类时,将具有以下功能:

>>>
>>>
>>>  pyramid = RightPyramid ( base = 2 , slant_height = 4 )>>>  pyramid . area ()20.0>>>  pyramid . area_2 ()20.0

It works! You’ve used super() to successfully navigate a complicated class hierarchy while using both inheritance and composition to create new classes with minimal reimplementation.

有用! 您已经使用super()成功地导航了复杂的类层次结构,同时使用继承和组合来创建具有最少重新实现的新类。

多种继承选择 (Multiple Inheritance Alternatives)

As you can see, multiple inheritance can be useful but also lead to very complicated situations and code that is hard to read. It’s also rare to have objects that neatly inherit everything from more than multiple other objects.

如您所见,多重继承可能很有用,但也会导致非常复杂的情况和难以阅读的代码。 很少有对象能够从多个其他对象中巧妙地继承所有内容。

If you see yourself beginning to use multiple inheritance and a complicated class hierarchy, it’s worth asking yourself if you can achieve code that is cleaner and easier to understand by using composition instead of inheritance.

如果您发现自己开始使用多重继承和复杂的类层次结构,那么值得去问问自己,是否可以通过使用合成而不是继承来实现更简洁易懂的代码。

With composition, you can add very specific functionality to your classes from a specialized, simple class called a mixin.

使用composition,您可以从一个专门的简单类(称为mixin)向类中添加非常特定的功能。

Since this article is focused on inheritance, I won’t go into too much detail on composition and how to wield it in Python, but here’s a short example using VolumeMixin to give specific functionality to our 3D objects—in this case, a volume calculation:

由于本文的重点是继承,因此我不会过多地讨论合成以及如何在Python中使用它,但这是一个使用VolumeMixin为我们的3D对象提供特定功能的简短示例-在这种情况下,是体积计算:

In this example, the code was reworked to include a mixin called VolumeMixin. The mixin is then used by Cube and gives Cube the ability to calculate its volume, which is shown below:

在此示例中,代码经过重新编写,以包含一个名为VolumeMixin的混合。 然后,mixin由Cube ,并使Cube能够计算其体积,如下所示:

>>>
>>> cube = Cube(2)>>> cube.surface_area()24>>> cube.volume()8
>>>

This mixin can be used the same way in any class that has an area defined for it and for which the formula area * height returns the correct volume.

可以在任何为其定义了面积且公式area * height返回正确体积的类中以相同方式使用此mixin。

super()回顾 (A super() Recap)

In this tutorial, you learned how to supercharge your classes with super(). Your journey started with a review of single inheritance and then showed how to call superclass methods easily with super().

在本教程中,您学习了如何使用super()来增强您的类。 您的旅程首先回顾了单个继承,然后展示了如何使用super()轻松调用超类方法。

You then learned how multiple inheritance works in Python, and techniques to combine super() with multiple inheritance. You also learned about how Python resolves method calls using the method resolution order (MRO), as well as how to inspect and modify the MRO to ensure appropriate methods are called at appropriate times.

然后,您学习了多重继承在Python中的工作方式,以及将super()与多重继承结合在一起的技术。 您还了解了Python如何使用方法解析顺序(MRO)解析方法调用,以及如何检查和修改MRO以确保在适当的时间调用适当的方法。

For more information about object-oriented programming in Python and using super(), check out these resources:

有关使用Python和使用super()进行面向对象编程的更多信息,请查看以下资源:

翻译自:

python super

转载地址:http://wcqwd.baihongyu.com/

你可能感兴趣的文章
HNOI2016
查看>>
JVM介绍
查看>>
将PHP数组输出为HTML表格
查看>>
Java中的线程Thread方法之---suspend()和resume() 分类: ...
查看>>
经典排序算法回顾:选择排序,快速排序
查看>>
BZOJ2213 [Poi2011]Difference 【乱搞】
查看>>
c# 对加密的MP4文件进行解密
查看>>
AOP面向切面编程C#实例
查看>>
Win form碎知识点
查看>>
避免使用不必要的浮动
查看>>
第一节:ASP.NET开发环境配置
查看>>
sqlserver database常用命令
查看>>
rsync远程同步的基本配置与使用
查看>>
第二天作业
查看>>
访问属性和访问实例变量的区别
查看>>
Spring MVC 异常处理 - SimpleMappingExceptionResolver
查看>>
props 父组件给子组件传递参数
查看>>
【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT
查看>>
十二种获取Spring的上下文环境ApplicationContext的方法
查看>>
UVA 11346 Probability 概率 (连续概率)
查看>>