面向对象之派生和组合
派生
- 派生是指,子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法
一、派生的方法
- 子类是必须要派生出自己的数据属性不然就无数据属性可用
- 子类无法使用父类中
__init__
定义的属性
class Person(object):
def __init__(self, name, age):
self.name = name
class Teacher(Person):
def __init__(self, name):
self.name = name
def get_name(self):
print(f'老师的名字是{self.name}')
teacher_1 = Teacher('Xanadu')
teacher_1.get_name() # 名字是Xanadu
- 那怎么样可以使用继承的父类中
__init__
定义的属性呢?有以下两种方法
[1]指名道姓的调用__init__
方法
class Person(object):
def __init__(self, name):
self.name = name
class Teacher(Person):
def __init__(self, name):
#指名道姓的使用父类中的__init__方法
Person.__init__(self, name)
self.name = name
def get_name(self):
print(f'老师的名字是{self.name}')
teacher_1 = Teacher('Xanadu')
teacher_1.get_name() # 老师的名字是Xanadu
[2]超类(super()
)
- 调用super()会得到一个特殊的对象
- 该对象专门用来引用父类的属性
- 且严格按照MRO规定的顺序向后查找
class Person(object):
def __init__(self, name):
self.name = name
class Teacher(Person):
def __init__(self, name):
super().__init__(name)
self.name = name
def get_name(self):
print(f'老师的名字是{self.name}')
teacher_1 = Teacher('Xanadu')
teacher_1.get_name() # 老师的名字是Xanadu
- 提示:在Python2中super的使用需要完整地写成
super(自己的类名,self)
,而在python3中可以简写为super(
) - 当你使用
super()
函数时,Python会在MRO列表上继续搜索下一个类 - 只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次
- 使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表
[3]小结
- 这两种方式的区别是:
- 方式一是跟继承没有关系的,而方式二的super()是依赖于继承的
- 并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
组合
- 在一个类中以另外一个类的对象作为数据属性,称为类的组合。
一、组合的使用
- 组合与继承都是用来解决代码的重用性问题。
- 不同的是:
- 继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;
- 而组合则是一种“有”的关系,比如工资有税,有交税的等级,老师有税前工资和税后工资,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合
class Level(object):
def __init__(self, days, posts):
self.days = days
self.posts = posts
self.daily = Daily(posts)
def get_level(self):
if int(self.days) * self.daily.get_daily() > 10000:
return 0.2
else:
return 0.1
class Daily(object):
def __init__(self, posts):
self.posts = posts
def get_daily(self):
if self.posts == '普通职员':
return 300
else:
return 500
class Tax(object):
def __init__(self, days, posts):
self.days = days
self.daily = Daily(posts)
self.level = Level(days, posts)
def get_tax(self):
return int(self.days) * self.daily.get_daily() * self.level.get_level()
class Wages(object):
def __init__(self, days, posts):
self.days = days
self.posts = posts
#工资有交税的等级
self.level = Level(days, posts)
# 工资有日薪
self.daily = Daily(posts)
# 工资有税
self.tax = Tax(days, posts)
def wages(self):
days = int(self.days)
print(f'税前工资是{days * self.daily.get_daily()}')
def true_wages(self):
days = int(self.days)
print(f'税后工资是{days * self.daily.get_daily() - self.tax.get_tax()}')
my_wages = Wages(30, '普通职员')
my_wages.wages() # 税前工资是9000
my_wages.true_wages() # 税后工资是8100.0
my_wages_1 = Wages(30, '经理')
my_wages_1.wages() # 税前工资是15000
my_wages_1.true_wages() # 税后工资是12000.0
- 此时对象my_wages集对象独有的属性、Wages类中的内容、Tax类中的内容于一身(都可以访问到),是一个高度整合的产物
- 当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
二、组合和继承的区别
- 组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,
[1]继承的方式
- 通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
- 当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人
[2]组合的方式
- 用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...