有一个着名的Python示例
class A(object):
def go(self):
print("go A go!")
class B(A):
def go(self):
super(B, self).go()
print("go B go!")
class C(A):
def go(self):
super(C, self).go()
print("go C go!")
class D(B,C):
def go(self):
super(D, self).go()
print("go D go!")
d = D()
d.go()
#go A go!
#go C go!
#go B go!
#go D go!
我有几个问题。第一个是B调用A和C调用A所以我希望A出现两次。第二个问题是订单。
答案 0 :(得分:5)
自Python 2.3以来,方法解析使用了一种名为C3 Linearization(借用Dylan)的算法。维基百科有a nice article on it。
顾名思义,这个想法是强制方法解析图是一条直线,即使继承图不是。这意味着A
在设计上不会出现两次。
为什么呢?嗯,首先,它完全避免了钻石问题"在许多其他语言中困扰多重继承。 (或者更准确地说,许多其他语言禁止MI或将其限制为纯粹的接口"因为它们没有解决问题,因为它存在于C ++中。)
最初的Python解释 - 包括它背后的动机 - 可以在The Python 2.3 Method Resolution Order中找到。这有点技术性,但如果您有兴趣,还值得一读。
您可能还想阅读the original Dylan paper,其中详细介绍了非线性MRO图表的错误,以及提出单调线性化的挑战(也就是说,它按照你期望的顺序进行,或者至少按照你预期的顺序进行,即使它是线性的,等等。
如果你想深入了解type()
如何在幕后工作,或者只是想看看2.3和3.7之间的变化(例如,__mro__
的创建方式和更新 - 虽然魔术3.x super
在其他地方),但实际上并没有比the CPython source更好的地方。
答案 1 :(得分:1)
类super
不只是恢复超类。它实例化一个对象,该对象在给定的方法解析顺序的上下文中恢复方法。每个班级都有一个 mro ,您可以通过__mro__
属性进行访问。
D.__mro__ # (D, B, C, A, object)
因此,当给定一个类和一个实例时,super
首先从该实例恢复 mro 。当您尝试从super
对象恢复属性时,它会从提供的具有此类属性的类之后的第一个类中返回该属性。
如果要在Python中实现super
的行为,它看起来就像这样。
class super:
def __init__(self, cls, instance):
if not isinstance(cls, type):
raise TypeError('super() argument 1 must be type')
if isinstance(instance, cls):
self.mro = type(instance).__mro__
elif isinstance(instance, type) and issubclass(instance, cls):
self.mro = instance.__mro__
else:
raise TypeError('super(type, obj): obj must be an instance or subtype of type')
self.cls = cls
self.instance = instance
def __getattr__(self, attr):
cls_index = self.mro.index(self.cls)
for supercls in self.mro[cls_index + 1:]:
if hasattr(supercls, attr): break
# The actual implementation binds instances to methods before returning
return getattr(supercls, attr)
回到您的示例,当您致电super(B, self).go
时,它会恢复__mro__
self
D
,其类型为go
。然后,它会从 mro 中具有此类属性的B
后的第一个类中选择self.__mro__
。
因此,在这种情况下(D, B, C, A, object)
为B
,go
后面具有属性C
的第一个类是A
而不是var dateTokens = "2018-03-13".split("-");
//creating date object from specified year, month, and day
var date1 = new Date(dateTokens[0],dateTokens[1] -1,dateTokens[2]);
//creating date object from specified date string
var date2 = new Date("2018-03-13");
console.log("Date1 in milliseconds: ", date1.getTime());
console.log("Date2 in milliseconds: ", date1.getTime());
console.log("Date1: ", date1.toString());
console.log("Date2: ", date2.toString());
}。
如果您想了解Python如何确定 mro 的详细信息,那么我建议abarnert's answer。