我需要创建一个扩展dict的类,然后遇到下图中愚蠢的例子说明的有趣问题。
为什么d.update()
忽略了班级的__getitem__
?
编辑:这是在python2.7中,它似乎不包含collections.UserDict 思考UserDict.UserDict是我尝试过的等价物,它越来越近了,但仍然表现得很有趣。
答案 0 :(得分:6)
这是open-closed-principle的一个例子(该类是为扩展而打开但是因修改而关闭)。这是件好事,因为它允许子类扩展或覆盖方法而不会无意中触发其他方面的行为更改而不会破坏类的不变量。
我们甚至也在纯python代码中执行此操作;例如,inside the pure python ordered dict code,__init__()
到update()
的班级本地通话是使用name mangling完成的。这允许子类格式覆盖update()
without accidentally breaking __init__()
。
有时,这很不方便。这意味着子类加密器必须覆盖他们想要更改其行为的每个方法,包括get()
,update()
和其他方法。但是,有一些抵消的好处(保护内部不变量,防止实现细节从抽象中泄漏,并允许用户假设这些方法彼此独立)。
这种风格(由Guido从一开始就选择)是内置类型的默认值(否则我们将永远对抗segfaulting不变违规)和一些纯python类。
我们在偏离默认值时进行记录。例如,cmd module使用framework design pattern,让用户定义各种do_action()方法。此外,一些http模块也是这样做的,特别是记录了用户的do_GET()
method被调用,这就是你如何附加自定义的HTTP事件处理程序。
如果没有专门记录的方法钩子(即上面列出的那些钩子或像dict.__missing__()
这样的方法,子类加法器应该假定方法独立性。否则,你怎么知道__getitem__()
是否调用get()
引擎盖下反之亦然?
FWIW,这不是Python特有的。它在面向对象编程中出现了很多。正确设计的类要么记录影响其他方法行为的根方法,要么假定它们是独立的。
可能需要有一个常见问题解答,但这里没有任何破坏或错误(除了Python有太多的dict变体可供选择)。如果有人错误地假设或认为__getitem__()
必须被其他访问者方法调用,他们会很快发现这个假设是错误的(即如果他们对代码进行了最小的测试)。