Ian*_*nSR 56 python class super
我到处都看到应该通过以下方式调用超类方法:
super(SuperClass, instance).method(args)
Run Code Online (Sandbox Code Playgroud)
这样做有什么不利之处:
SuperClass.method(instance, args)
Run Code Online (Sandbox Code Playgroud)
unu*_*tbu 105
考虑以下情况:
class A(object):
def __init__(self):
print('Running A.__init__')
super(A,self).__init__()
class B(A):
def __init__(self):
print('Running B.__init__')
# super(B,self).__init__()
A.__init__(self)
class C(A):
def __init__(self):
print('Running C.__init__')
super(C,self).__init__()
class D(B,C):
def __init__(self):
print('Running D.__init__')
super(D,self).__init__()
foo=D()
Run Code Online (Sandbox Code Playgroud)
所以这些类形成了一个所谓的继承钻石:
A
/ \
B C
\ /
D
Run Code Online (Sandbox Code Playgroud)
运行代码产生
Running D.__init__
Running B.__init__
Running A.__init__
Run Code Online (Sandbox Code Playgroud)
这是因为不好C的__init__将被跳过.其原因是因为B的__init__调用A的__init__直接.
目的super是解决继承钻石问题.如果你取消评论
# super(B,self).__init__()
Run Code Online (Sandbox Code Playgroud)
和评论
A.__init__(self)
Run Code Online (Sandbox Code Playgroud)
代码产生更可取的结果:
Running D.__init__
Running B.__init__
Running C.__init__
Running A.__init__
Run Code Online (Sandbox Code Playgroud)
现在__init__调用所有方法.请注意,在您定义时,B.__init__您可能会认为这super(B,self).__init__()与调用相同A.__init__(self),但您错了.在上述情况下,super(B,self).__init__()实际上是通话C.__init__(self).
圣抽烟, B一无所知C,却super(B,self)知道调用C的__init__?原因是因为self.__class__.mro()包含C.换句话说,self(或在上面,foo)知道C.
所以要小心 - 这两个是不可替代的.它们可以产生截然不同的结果.
使用super 有陷阱.它在继承图中的所有类之间需要相当程度的协调.(例如,它们必须具有相同的呼叫签名__init__,因为任何特定的__init__人都不知道__init__ super下一个可能会调用哪个,或者使用**kwargs.)此外,您必须始终如一地使用它super.略过一次(如上例所示),你就失败了super.请参阅链接以了解更多陷阱.
如果你完全控制你的类层次结构,或者你避免继承钻石,那么就没有必要了super.
虽然你的例子有点误导,但没有任何惩罚.在第一个例子中,它应该是
super(SubClass, instance).method(args) # Sub, not SuperClass
Run Code Online (Sandbox Code Playgroud)
这引导我引用Python文档:
有两种典型的用例
super.在具有单继承的类层次结构中,super可以用于引用父类而不显式命名它们,从而使代码更易于维护.这种用法与super其他编程语言的使用密切相关.第二个用例是在动态执行环境中支持协作多重继承.此用例是Python独有的,在静态编译语言或仅支持单继承的语言中找不到.这使得实现"菱形图"成为可能,其中多个基类实现相同的方法.好的设计要求此方法在每种情况下都具有相同的调用签名(因为调用的顺序是在运行时确定的,因为该顺序适应类层次结构中的更改,并且因为该顺序可以包括在运行时之前未知的兄弟类).
基本上,通过使用第一种方法,您不必对单类层次结构中的父类进行硬编码,并且在使用多个层次结构时,您根本无法使用第二种方法(高效/有效)执行所需操作遗产.
| 归档时间: |
|
| 查看次数: |
27890 次 |
| 最近记录: |