眼看着五一假期离我越来越近,我想要休假的心情也越来越迫切,仿佛码字都变得更快乐了∑)
在昨天 什么是类.的最后面,写了一个烹饪的类,但它还是有一些问题的:
原来的方法是这么写的:
def fry(self): #方法定义
self.In_One = self.In_One + ' 搅匀翻炒 '
self.In_Two = self.In_Two + ' 切片入锅 '
return self.In_One + self.In_Two + '放盐翻炒 摆盘'
虽然看起来是可以炒一切了,但是它有个弊端就是,只能是什么什么炒鸡蛋:)如果我想做黄瓜炒木耳呢?或者茄子炖土豆呢?
强行把这个类实例化的结果可能是:
土豆 搅匀翻炒 茄子 切片入锅 放盐翻炒 摆盘:)
而这,往往是我们不希望发生的。这种时候,就需要我们改一下类的源代码——可这跟不断地自定义新函数又有什么区别呢?类本身是不是有什么改变方法/属性的技术呢?
所以!重点来了,类的继承!
继承,就是在继承类原有功能的基础上,增加新的功能 / 属性 / 方法,新形成的类叫子类,被继承的叫父类
继承的基本格式
class 子类名(父类名)
在继承的时候,还可以多个父类一起继承给同一个子类,父爱如山崩地裂/doge
class 子类名(父类名1,父类名2, ....)
那接下来就继承一下昨天的烹饪类/doge
继承属性、添加属性
继承属性有两种基本写法:
第一种是用super().函数,第二种则是直接用父类名继承,这两种均会在实例1种详细叙述。
实例1:继承单个方法
先回顾一下昨天的烹饪类是怎么写的
class Cook():
def __init__(self,one,two):
self.In_One = one
self.In_Two = two
def fry(self):
self.In_One = self.In_One + ' 搅匀翻炒 '
self.In_Two = self.In_Two + ' 切片入锅 '
return self.In_One + self.In_Two + '放盐翻炒 摆盘'
breakfast = Cook('鸡蛋','西红柿')
print('%s'%( breakfast.fry() ))
实例化输出:
鸡蛋 搅匀翻炒 西红柿 切片入锅 放盐翻炒 摆盘
现在,我们想做茄子炖土豆了/doge,就要在原有类的基础上,继承一个新的子类,并在子类里添加炖的功能,写法如下:
class CookA(Cook):
def __init__(self,one,two):
super().__init__(one,two)
def stew(self):
return '加水,'+ self.In_One + self.In_Two + '入锅'
- super(). :实现父类与子类的关联,当父类有参数时,就要用super()函数同步除了self以外的参数(注意括号右下角还有个点“ . ”)
- 第一个__init__后面的参数依旧是(self,参数1,参数2…)若有增加的,则把它们也都写在里面,增加属性会在稍后讲到
子类实例化:
lunch = CookA('土豆','茄子')
print('%s'%( lunch.stew() ))
输出:
加水,土豆茄子入锅
在super的说明里,我着重强调了一下除了self以外的参数,如果我们在之前写成super(self,one,two)又会发生什么?
刚刚是用的super()函数来同步参数,其实除了super ,还有另一种写法:
唯一不同的就是定义属性的函数,其他的部分全部相同就不赘述了
def __init__(self,one,two):
Cook.__init__(self,one,two)
这种写法则是用的父类名来继承属性,不过这次就要再加上 “self” 了。
- 如果现在的类里面,属性太少了,我们不再只是输入两个材料,我们要做一个,佛跳墙呢/doge
class CookA(Cook):
def __init__(self,one,two,many):
super().__init__(one,two)
self.In_many = many
def stew(self):
return '加水,'+ self.In_many +'入锅'
用父类名继承并添加元素也是同样的写法:
def __init__(self,one,two,many):
Cook.__init__(self,one,two)
self.In_many = many
实例2:继承多个方法
'''第一个类'''
class Cook()
'''继承的子类'''
class CookA(Cook):
'''写一个新的类'''
class CookB():
def __init__(self,A,B):
self.A = A
self.B = B
def fry(self):
return '开大火爆炒'+ self.A + self.B
接下来,我们把CookA 和 CookB 作为父类(A的方法是stew,B的方法是fry),继承给 CookC
(为什么要先写B后写A?划重点,一会说)
class CookC(CookB,CookA):
def __init__(self,one,two,many,A,B):
CookA.__init__(self,one,two,many)
CookB.__init__(self,A,B)
CookC的方法就不写了,直接继承AB的属性以后,我们分别调用A和B的方法:
Out = CookC('A','S','D','F','G')
print('%s'%( Out.stew() ))
print('%s'%( Out.fry() ))
加水,ASD入锅
开大火爆炒FG
而在定义CookC类的时候,先A后B呢,class CookC(CookA,CookB):
Out = CookC('A','S','D','F','G')
print('%s'%( Out.stew() ))
print('%s'%( Out.fry() ))
加水,ASD入锅
开大火爆炒AS
这是为什么?
其实用下面的例子讲更为清楚:
现在我把CookC的父类改成Cook与CookB,二者的方法都是fry,但是内容分别为:
return '加水,'+ self.In_One + self.In_Two + self.In_many +'入锅'
return '开大火爆炒'+ self.A + self.B
现在再来Out = CookC(‘A’,‘S’,‘D’,‘F’,‘G’) 以后 print(’%s’%( Out.fry() )),我们看一下输出结果:
A 搅匀翻炒 S 切片入锅 放盐翻炒 摆盘
可以发现,现在实际输出的是Cook 的fry,而不是CookB的,这是因为,当父类们有相同的方法时,默认寻找并使用从左至右开始找到的第一个方法。
实例3:重写方法
当我们发现父类的这个方法不好用的时候,我们可以在继承父类的同时重新定义一下父类的方法:(写在子类方法的下面就可)
class CookA(Cook):
def __init__(self,one,two,many):
Cook.__init__(self,one,two)
self.In_many = many
def stew(self):
return '加水,'+ self.In_One + self.In_Two + self.In_many +'入锅'
def fry(self):
return '关火,不炒了'
接下来输入材料,输出的则是重写了以后的方法
lunch = CookA('土豆','茄子','balabala')
print('%s'%( lunch.fry() ))
关火,不炒了
而这时我们不再继承父类,直接把父类实例化的话,输出还是原本的那个方法:
breakfast = Cook('鸡蛋','西红柿')
print('%s'%( breakfast.fry() ))
鸡蛋 搅匀翻炒 西红柿 切片入锅 放盐翻炒 摆盘
…
…
以上的内容其实是为了继承而继承的,如果真要一个个改也不是不行:)但这正像前文所说:这和不断地自定义新函数有什么区别?实际上,需要使用继承的原因没必要像前文那样是为了介绍而说得这么牵强,这里举两个例子各位就明白了:
- 这个类已经被其他程序使用了,如果改动类,相应的程序都要被牵连
- 有时候,我们用的第三方类,并不会提供源代码
由此才会有在遇到以上问题时,为了达到改造的目的而生的——继承 !
我是康.,立志做一名能帮助到大家的博主!在更新完Python系列后会再开机器学习的系列,对此类文章感兴趣的小伙伴欢迎与我一起学习,共同进步/doge,下篇文章见!