recommended principles of object-oriented programming中的一个是Liskov substitution principle:子类应该以与其基类相同的方式运行(警告:这实际上不是Liskov原则的正确描述:请参阅PS)。
是否建议它也适用于构造函数?我主要考虑Python及其__init__()
方法,但这个问题适用于任何具有继承性的面向对象语言。
我问这个问题,因为有一个子类从一个或多个类继承,提供一些不错的默认行为(比如从Python继承字典,以便obj['key']
适用于新课)。但是,允许子类完全像字典一样使用并不总是自然或简单的:有时候构造函数参数只与特定用户子类相关(例如,代表一组串行端口的类)更好可能希望表现得像ports['usb1']
是USB端口#1等字典。这种情况的推荐方法是什么?具有与其基类完全兼容的子类构造函数,并通过对象工厂函数生成实例,该函数采用简单,用户友好的参数?或者只是编写一个类构造函数,其参数集不能直接赋予其基类的构造函数,但从用户的角度来看哪个更合乎逻辑?
PS :我误解了上面的Liskov原则:下面的Sven的评论指出了一个子类的对象应该像超类的对象(子类本身)一样的事实不必像超类一样;特别是,它们的构造函数不必具有相同的参数[signature])。
答案 0 :(得分:4)
根据要求,我发布了以前评论的答案。
链接的维基百科文章中定义的原则是“如果S是T的子类型,那么类型T的对象可以用类型S的对象替换”。它不会读取“子类应该以与其基类相同的方式运行”。在考虑构造函数时,差异很重要:维基百科版本仅讨论子类型的对象,而不是类型本身。对于一个对象,已经调用了构造函数,因此该原则不适用于构造函数。这也是我应用它的方式,以及它在标准库中的应用方式(例如defaultdict
和dict
)。
多重继承中的构造函数可能无法以语言无关的方式进行讨论。在Python中,有两种方法。如果您的继承图包含菱形图案,并且您需要确保所有构造函数都只调用一次,则应使用super()
并遵循Raymond Hettinger的文章Python's super()
considered super中“实用建议”部分中描述的模式。如果你没有钻石(包括object
除外),你也可以对所有基类构造函数使用显式基类调用。