请考虑以下代码示例:使用self.method()
与super.method()
之间的区别是什么。如果class B
继承自class A
,但尚未覆盖方法p
,那么super().p()
和self.p()
不会做同样的事情吗?哪种方式更正确?我假设使用super()
将显式调用基类方法,而如果某人覆盖方法p,self.p()
可能会遇到问题。
class A:
def p(self):
print("A")
class B(A):
def c(self):
self.p()
def d(self):
super().p()
>>> b = B()
>>> b.c()
A
>>> b.d()
A
答案 0 :(得分:1)
在当前示例中确实没有区别,super().p()
和self.p()
最终都会调用相同的方法。这是因为找不到p
类的其他 B
属性。
哪一个更正确取决于您希望在其他代码引入p
某处时发生的情况。这可以在实例上,B
类本身(稍后在应用程序开发周期中,由您或其他开发人员),或者在继承自B
的新类上。
当您在p
,self
和super().p()
上添加另一个self.p()
可调用属性(比如说新方法)时,会产生不同的结果。您可以直接在实例或B
类上添加此类属性,也可以创建一个继承自C
的类B
并定义该方法。在所有3个案例中,self.p()
会找到新定义,而super()
则不会。请注意,self
也直接在实例本身上查看属性,而super()
仅考虑父类的类属性。
演示在实例上添加属性; lambda
只是定义函数的一种简短方法:
>>> b_instance = B()
>>> b_instance.p = lambda: print('p directly defined on the b instance')
>>> b_instance.c()
p directly defined on the b instance
>>> b_instance.d()
A
直接在类上添加方法进行演示(可以在定义类之后在类上添加方法作为新属性):
>>> B.p = lambda self: print('The p method defined on B')
>>> b_instance = B()
>>> b_instance.c()
The p method defined on B
>>> b_instance.d()
A
>>> del B.p # delete the new method again to go back to the original state
使用新课程进行演示:
>>> class C(B):
... def p(self):
... print('The p method defined on C')
...
>>> c_instance = C()
>>> c_instance.c()
The p method defined on C
>>> c_instance.d()
A
因此,self
和super()
之间的区别在于搜索属性的位置。 self
首先在实例本身上开始,然后从type(self)
开始的类层次结构。 super()
仅查看方法解析顺序中当前类(定义方法)之后的类(记录在类__mro__
属性中)。
不同类别的MRO是:
>>> A.__mro__
(<class '__main__.A'>, <class 'object'>)
>>> B.__mro__
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
非常简单,因为你没有使用多重继承。
对于上面的示例,self.p()
查看:
__dict__
字典,如果存在p
密钥,则调用该值。这是第一个例子。type(instance).__mro__
中的每个班级,因此根据示例,搜索将包括C
,B
,A
以及object
的所有内容。并且p
属性位于第二个示例中的B.p
,第三个示例中为C.p
。
但在上面所有示例中,super().p()
搜索仅查看B.__mro__
,首先查找B
,然后从列表中的下一个类开始,找到A.p
。
最常见的假设是,您希望能够覆盖子类中的p
,因此对于大多数用例,您必须坚持使用self.p()
。< / p>
答案 1 :(得分:0)
正如您自己猜测的那样,如果您的继承类( B )覆盖了您的函数( p ),则只会有所不同。
根据上下文的不同,您可能希望强制类始终使用继承的函数,但是对于通常的实践,我总是会引用自己的函数(因为如果将来它可能会出现这种情况)有一个原因)。