如果子类支持该方法,如何从基类方法调用子类方法?最好的方法是什么?举例说明,我有一种保护我家的动物:如果有人走过它会看起来很生气,如果可以的话就会吠叫。
示例代码:
class Protector(object):
def protect(self):
self.lookangry()
if hasattr(self, 'bark'):
self.bark()
class GermanShepherd(Protector):
def lookangry(self):
print u') _ _ __/°°¬'
def bark(self):
print 'wau wau'
class ScaryCat(Protector):
def lookangry(self):
print '=^..^='
我可以想到很多替代实现:
hasattr
。try: self.bark() except AttributeError: pass
但是它也会捕获bark
NotImplementedError
并检查NotImplementedError
而不是AttributeError
。有了这个解决方案,Pylint会抱怨我忘记覆盖ScaryCat
中的抽象方法。在抽象类中定义一个空树皮方法:
class Protector(object):
def protect(self):
self.lookangry()
self.bark()
def bark(self):
pass
我在Python中认为他们通常应该是一种做某事的方法。在这种情况下,我不清楚哪个。这些选项中哪一个最具可读性,最不可能在更改内容时引入错误,并且最符合编码标准,尤其是Pylint?是否有更好的方法来做到我错过了?
答案 0 :(得分:2)
在我看来,你正在考虑继承错误。基类应该封装在任何子类之间共享的所有内容。如果某些内容未被所有子类共享,则根据定义它不属于基类。
所以你的陈述“如果有人走过它会看起来很生气,如果它可以”吠叫“对我来说没有意义。 “bark if can can”部分不会在所有子类之间共享,因此不应在基类中实现。
应该发生的是您要强制的子类将此功能添加到protect()
方法。如:
class Protector():
def protect(self):
self.lookangry()
class GermanShepherd(Protector):
def protect(self):
super().protect() # or super(GermanShepherd, self).protect() for Python 2
self.bark()
这样所有子类都将lookangry()
,但实现bark()
方法的子类将把它作为超类protect()
方法的扩展功能的一部分。
答案 1 :(得分:1)
你错过了一种可能性:
定义一个引发bark
的{{1}}方法,如同您的选项4一样,但不将其抽象化。
这消除了PyLint的抱怨 - 更重要的是,消除了它抱怨的合法问题。
至于你的其他选择:
NotImplementedError
是不必要的LBYL,通常不是Pythonic。hasattr
块内执行except
来处理bark = self.bark
问题,然后在try
通过时执行bark()
。这有时是必要的,但它有点笨拙并且没有“修复”的事实应该会让你知道它的价值多久。ManWithSidekick.bark()
self.sidekick.bark()
怎么办?您如何区分AttributeError
那里?)所以,留下了2,4.5和5。
我认为在大多数情况下,4.5或5都是正确的选择。他们之间的区别不是务实,而是概念性的:如果ScaryCat
动物悄悄地吠叫,使用选项5;如果没有,那么吠叫必须是保护的可选部分,并非所有保护者都这样做,在这种情况下使用选项4.5。
对于这个玩具示例,我想我会使用选项4.5。而且我认为你提出的大多数玩具例子都会出现这种情况。
然而,我怀疑大多数现实生活中的例子会有很大不同:
bark
要么由所有子类实现,要么不被超类调用。bark
默默地不是ScaryCat
所做的事情,但parse_frame
默默地是ProxyProtocol
所做的事情。答案 2 :(得分:1)
我认为6.)可能是Protector
类只使得抽象所需的基本共享方法,同时将额外的方法留给其继承人。当然,这可以分成更多的子类,参见https://repl.it/repls/AridScrawnyCoderesource(用Python 3.6编写)
class Protector(object):
def lookangry(self):
raise NotImplementedError("If it can't look angry, it can't protect")
def protect(self):
self.lookangry()
class Doggo(Protector):
def bark(self):
raise NotImplementedError("If a dog can't bark, it can't protect")
def protect(self):
super().protect()
self.bark()
class GermanShepherd(Doggo):
def lookangry(self):
print(') _ _ __/°°¬')
def bark(self):
print('wau wau')
class Pug(Doggo):
# We will not consider that screeching as barking so no bark method
def lookangry(self):
print('(◉ω◉)')
class ScaryCat(Protector):
def lookangry(self):
print('o(≧o≦)o')
class Kitten(Protector):
pass
doggo = GermanShepherd()
doggo.protect()
try:
gleam_of_silver = Pug()
gleam_of_silver.protect()
except NotImplementedError as e:
print(e)
cheezburger = ScaryCat()
cheezburger.protect()
try:
ball_of_wool = Kitten()
ball_of_wool.protect()
except NotImplementedError as e:
print(e)