76.调用为关联的超类(继承的类)构造函数
先举个例子:
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print('Aaaah ...') self.hungry = False else: print('No, thanks!')class SongBird(Bird): def __init__(self): self.sound = 'Squawk!' def sing(self): print(self.sound)输出:>>> b=Bird()>>> b.eat()Aaaah ...>>> b.eat()No, thanks!>>> sb=SongBird()>>> sb.eat()Traceback (most recent call last):File "<pyshell#84>", line 1, in <module>sb.eat()File "E:/python/子类.py", line 5, in eatif self.hungry:AttributeError: 'SongBird' object has no attribute 'hungry'
可以看到这个sb.eat()报错了,为什么呢?因为在SongBird中重写了构造函数,但新的构造函数没有包含任何初始化属性hungry的代码。我们可以将重写的构造函数去掉试一下:
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print('Aaaah ...') self.hungry = False else: print('No, thanks!')class SongBird(Bird): def sing(self): print(self.sound)输出:>>> b=SongBird()>>> b.eat()Aaaah ...>>> b.eat()No, thanks!
可以看出当去掉重写的构造函数之后,错误没有了,所以要解决这个问题以下有两种方法:方法一:就是调用未关联的超类构造函数
class SongBird(Bird): def __init__(self):Bird.__init__(self)self.sound = 'Squawk!' def sing(self): print(self.sound)输出:>>> sb=SongBird()>>> sb.eat()Aaaah ...>>> sb.eat()No, thanks!
结论:对实例调用方法时,方法的参数self将自动关联到实例;如果通过类调用方法(如:Bird.__init__),就没有实例与其相关联;所以可以随便设置参数self。方法二:使用super函数
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print('Aaaah ...') self.hungry = False else: print('No, thanks!')class SongBird(Bird):def __init__(self):super().__init__()self.sound='Squawk'def sing(self): print(self.sound)输出:>>> b=SongBird()>>> b.sing()Squawk>>> b.eat()Aaaah ...>>> b.eat()No, thanks!
调用super函数时,将当前类和当前实例作为参数,对其返回的对象调用方法时,调用的将是超类(而不是当前类)的方法。
super优点总结:1.即使有多个超类,也是需要调用函数super一次,但是所有的超类的构造函数也使用super函数;2.使用super函数比调用未相关联的构造函数要好的多;3.无需关心super返回的是什么(只需要假定返回的是所需要的超类即可);但是事实上返回的是一个super对象,这个对象将负责为你执行方法解析。当访问它的属性时,它将在所有的超类中查找,直到找到指定的超类的属性或者报错。4.相对于旧式类,如果两个超类从同一个类派生出来,在使用新式类和函数super时将自动得到处理(而且无需知道super工作原理)。