Python v3.7.0
方案一(推荐):定义抽象基类,只要把一个方法定义成抽象方法,那解释器就会要求子类必须重写这个方法,要注意的是,如果抽象方法没有被重写,那么子类在实例化时,就会抛出TypeError异常,而不需要等到调用函数。
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def speak(self):
pass
class Dog(Animal):
def run(self):
pass
if __name__ == '__main__':
dog = Dog()
运行以上代码,会抛出异常:
TypeError: Can't instantiate abstract class Dog with abstract methods speak
只有在Dog子类中,重写speak
方法,才可以正常实例化子类。
方案二:指定父类方法抛出NotImplementedError异常
class Animal1():
def speak(self):
raise NotImplementedError
class Dog1(Animal1):
def run(self):
pass
if __name__ == '__main__':
dog = Dog1()
dog.speak()
子类中若没有重写speak
方法,也可以正常实例化,但是调用此方法时,就会抛出NotImplementedError
异常;
补充:
- 在父类中定义的私有方法,其作用范围仅在当前类,若在子类中重写,实际上并不会起效果,原因:以双下划线前缀开头的属性或方法,Python解释器会重写其名称,以便在类被扩展的时候不容易产生冲突,这被称之为名称修饰(name mangling),如下所示:
class Test:
def __init__(self):
self.__foo = True
def __bar(self):
return "bar"
t = Test()
print(dir(t))
print(t._Test__foo)
print(t._Test__bar())
输出内容如下,注意列表前两个值,这同时也说明在Python中是没有绝对私有的变量或方法的。
['_Test__bar', '_Test__foo', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
True
bar
- 在类的继承中,如果在子类中重写了父类方法,但有时也希望能同时实现父类的功能,最常见的场景之一就是父类构造方法中的初始值无法被继承,可以在子类中使用
super
函数来调用父类中的方法,特别是多重继承的情况;如下面的例子:
class Animal:
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print('No!')
else:
print('Yes!')
class Bird(Animal):
def __init__(self):
self.song = '~~~'
def sing(self):
print(self.song)
bird = Bird()
bird.sing() # 正常
bird.eat() # 抛出异常:AttributeError: 'Bird' object has no attribute 'hungry'
解决的方法是在子类的构造函数中,使用super方法调用父类的构造函数,如下:
class Bird(Animal):
def __init__(self):
super().__init__()
self.song = '~~~'
网友评论