一、继承的概念
python面向对象中的继承指的是多个类之间的从属关系,即子类继承父类的所有属性和方法(除了私有属性和私有方法)。
经典类:不由任意内置类型派生出的类,称之为经典类。
语法:
class 类名:
代码
在python中,所有类默认继承自object类,object类是顶级类或者说是基类,其他子类叫派生类。
类名(),()中间写的内容就表示继承,父类写在()里面。如果类名后面没有()或者()内部没有内容,则表示默认继承自object类。
新式类语法:
class 类名(object):
代码
例如:
# 定义父类
class A(object):
def __init__(self):
self.age = 1
def print_info(self):
print(self.age)
# 定义子类
class B(A): # 子类B继承自父类A
pass
res = B()
res.print_info()
# 结果为1 即可以获取到A类中的所有属性和方法
print(res.age)
# 结果为1
二、单继承
举例:狗狗豆子的爸爸是灰白毛而且喜欢吃香肠,豆子继承爸爸的属性和方法也是灰白色,也喜欢吃香肠。
# 定义爸爸类
class Dad(object):
def __init__(self):
self.color = '灰白色'
def hobby(self):
print('喜欢吃香肠')
# 定义孩子类
class Son(Dad):
pass
douzi = Son()
print(douzi.color)
# 结果为灰白色
douzi.hobby()
# 结果为喜欢吃香肠
总结:
1、子类在继承的时候,在定义子类的时候()里面要写父类的类名;
2、父类的属性、方法都会被子类继承(除私有属性和私有方法)。
三、多继承
所谓多继承就是指一个子类同时继承多个父类。
举例:狗狗豆子的爷爷是灰色毛,喜欢吃的事物是大肉丸子,爸爸是灰白毛而且喜欢吃香肠,豆子同时继承自爷爷和爸爸的属性和方法。
# 定义爷爷类
class Grandfather(object):
def __init__(self):
self.color = '灰色'
def food(self):
print('喜欢吃大肉丸子')
# 定义爸爸类
class Dad(object):
def __init__(self):
self.color = '灰白色'
self.eye = '棕色'
def dad_food(self):
print('喜欢吃香肠')
# 定义孩子类
class Son(Grandfather, Dad):
pass
douzi = Son()
print(douzi.color)
# 结果是灰色
# 此时color继承自爷爷而不是爸爸,这是因为是按照顺序继承的,当多个父类的属性名或方法名相同时,则继承自第一个父类(继承按照__mro__的顺序)。
print(Son.__mro__)
# 结果为(<class '__main__.Son'>, <class '__main__.Grandfather'>, <class '__main__.Dad'>, <class 'object'>)
print(douzi.eye)
# 此时会报错
# 属性的继承直接在第一个父类中的初始化的(__init__())(这个是默认直接继承的)属性中去查找,如果第一个父类中没有这个属性就会报错。
douzi.food()
# 结果是喜欢吃大肉丸子
douzi.dad_food()
# 结果是喜欢吃香肠
总结:
1.多继承可以继承多个父类,也继承所有父类的属性和方法(除了私有属性和私有方法);
2.如果多个父类中有同名的属性和方法,则默认继承第一个父类的属性和方法(根据类中魔法方法mro的顺序来查找的);属性默认只继承第一个父类,方法按照顺序继承;
3.多个父类中,不同名的属性和方法,之间不会有任何影响。
四、子类重写父类同名的方法与属性
举例:豆子继承了爸爸的
# 定义爸爸类
class Dad(object):
def __init__(self):
self.color = '灰白色'
self.eye = '棕色'
def dad_food(self):
print('喜欢吃香肠')
# 定义孩子类
class Son(Dad):
def __init__(self):
self.color = '白色'
self.eye = '黑色'
def food(self):
print('豆子喜欢吃鸡腿')
douzi =Son()
print(Son.__mro__)
# 结果为(<class '__main__.Son'>, <class '__main__.Dad'>, <class 'object'>)
print(douzi.color)
# 结果为白色
print(douzi.eye)
# 结果为黑色
douzi.dad_food()
# 结果为喜欢吃香肠
douzi.food()
# 结果为豆子喜欢吃鸡腿
总结:
1.子类和父类具有同名的方法和属性,默认使用子类的同名方法和属性;
2.子类定义了初始化属性时,就不再继承父类的属性,若需要的属性子类中没有,则会报错,而不到父类的属性中查找;
3.子类的魔法属性mro决定了属性和方法的查找顺序。
五、子类调用父类同名的方法与属性
举例:豆子不仅有自己独有的喜欢吃的食物,还喜欢吃爸爸喜欢吃的食物。
# 定义爸爸类
class Dad(object):
def __init__(self):
self.color = '灰白色'
self.eye = '棕色'
def food(self):
print('喜欢吃香肠')
# 定义孩子类
class Son(Dad):
def __init__(self):
self.color = '白色'
self.eye = '黑色'
def food(self):
self.__init__()
# 运用该类的属性重新初始化,防止运用了封装的其他父类的内容而用不了本类的属性了
print('豆子喜欢吃鸡腿')
def dad_food(self): # 访问Dad的food方法,将Dad的food方法封装起来
Dad.__init__(self)
Dad.food(self) # 父类名.父类的方法名()
def dad_bark(self): # 将Dad的bark方法封装起来,以便访问
Dad.__init__(self)
Dad.bark(self)
# 子类重写了父类的同名方法和属性只是将原来继承的覆盖了,继承的内容还在;
# 所以只要把父类的同名方法和属性再次封装就可以获取了;
# 再次封装就是在子类里面再定义一个方法。
douzi =Son()
print(douzi.color)
# 结果为白色
print(douzi.eye)
# 结果为黑色
douzi.dad_food()
# 结果为喜欢吃香肠
douzi.dad_bark()
# 结果为汪!汪!汪!
douzi.food()
# 结果为豆子喜欢吃鸡腿
总结:无论何时何地,self都表示的是子类的对象,通过传递self参数,来控制属性和方法的访问和修改。