本文共 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:
在本教程中,您将了解以下内容:
super()
function workssuper()
function in single inheritance workssuper()
function in multiple inheritance workssuper()
函数如何工作 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技能提升到新水平所需的路线图和心态。
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
.
在这里,有两个类似的类: Rectangle
和Square
。
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.
因为Square
和Rectangle
.__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()
方法并打印16
。 Square
类从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__()
。 由于Cube
从Square
继承而来, .__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()
如何启用该功能。
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:
我是一个非常有远见的人,我发现图表对于理解这样的概念非常有帮助。 下图显示了一个非常简单的多重继承方案,其中一个类从两个不相关的(同级)超类继承:
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
:
为了更好地说明运行中的多重继承,下面是一些代码供您试用,以显示如何从Triangle
和Square
构建一个正确的金字塔(具有正方形底的金字塔):
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
类,它们从Square
和Triangle
继承。
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
类的任何继承属性。 后面的示例将充分利用Triangle
和Square
的继承。
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:
但是,问题在于两个超类( Triangle
和Square
)都定义了.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()
.
您可以从几何图形类中将其识别为三角形面积的公式。 否则,如果您像我一样,则可能已经向上滚动到Triangle
和Rectangle
类定义,并在Triangle.area()
看到了相同的代码。
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
.
这里的问题是,解释器在Square
和Rectangle
之前的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:
您需要做两件事来解决此问题:
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
.
Redesign all the .__init__()
calls to take a keyword dictionary. See the complete code below.
用super()
调用的所有方法都需要对其方法的超类版本进行调用。 这意味着您需要将super().__init__()
到Triangle
和Rectangle
的.__init__()
方法中。
重新设计所有.__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 | 命名参数 | kwargs kwargs |
---|---|---|---|---|
RightPyramid RightPyramid | base , base slant_height slant_height | |||
Square Square | length length | base , base height height | ||
Rectangle Rectangle | length , length , width width | base , base height height | ||
Triangle Triangle | base , base height height |
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()
成功地导航了复杂的类层次结构,同时使用继承和组合来创建具有最少重新实现的新类。
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/