Day 5-2 类的继承和派生,重用

时间:2023-03-09 19:41:45
Day 5-2 类的继承和派生,重用

类的继承

派生

在子类中重用父类

组合

抽象类

定义:

承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题.

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可以成为基类或超类,新建的类称为派生类或子类.

 # 我们定义的2个英雄都有一些相似的特征和技能.都属于英雄类,那么我们就可以定义个英雄类,然后让英雄继承英雄类的特征和技能

 class Hero:
def __init__(self, name, life_value, aggressivity):
self.name = name
self.life_value = life_value
self.aggressivity = aggressivity def attck(self,enemy):
enemy.life_value -= self.aggressivity class Garen(Hero):
pass class Riven(Hero):
pass print(Garen.__bases__) # 查看Graren的父类.
g1 = Garen("草丛伦", 100, 50)
r1 = Riven("兔女郎", 80, 60)
print(r1.life_value)
# A, 我们通过Garen这个类,来产生一个对象g1.但是Garen这个类中,我们并未定义__init__方法.但是我们也定义成功了,并没有报错.为什么呢?
# B, 因为Garen这个类继承了Hero这个父类中的数据属性和函数属性.

继承类和查看父类

提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

派生

当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。简单的来说,派生就是子类自己定义自己独有的特征或方法.

继承的实现原理

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表.

>>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>,
<class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

所有父类的MRO列表并遵循如下三条准则:

  1. 子类会先于父类被检查
  2. 多个父类会根据它们在列表中的顺序被检查
  3. 如果对下一个类存在两个合法的选择,选择第一个父类

继承的查找:

 #验证多继承情况下的属性查找

 class A:
# def test(self):
# print('from A')
pass class B(A):
# def test(self):
# print('from B')
pass class C(A):
# def test(self):
# print('from C')
pass class D(B):
# def test(self):
# print('from D')
pass class E(C):
# def test(self):
# print('from E')
pass class F(D,E):
# def test(self):
# print('from F')
pass #F,D,B,E,C,A print(F.mro())
# f=F()
# f.test()

查找方式

在PY3中,都是新式类,没有经典类了.

经典类:在py2中.定义一个类.class Her0().如果括号里,没有继承基类object.它就是一个经典类.如果class Hero(object),那么就是一个新式类

py3中.如果一个类没有继承,那么默认继承object.

子类中重用父类

方式1,指名道姓的方式.(不依赖与继承)

 class Hero:
def __init__(self, name, life_value, aggressivity):
self.name = name
self.life_value = life_value
self.aggressivity = aggressivity def attck(self,enemy):
enemy.life_value -= self.aggressivity class Garen(Hero): def __init__(self, name, life_value, aggressivity, weapon):
Hero.__init__(self,name, life_value, aggressivity) # 指名道姓的调用父类中的方法.
self.weapon = weapon def attck(self,enemy):
Hero.attck(self,enemy) # 指名道姓的调用父类中的方法.
print("in Garen class") class Riven(Hero):
pass g1 = Garen("草丛伦", 100, 50,"黑切") print(g1.__dict__) # 查看g1的dict中,已经有了黑切.

指名道姓法

方式2,super()  (依赖于继承)

 # 方式2, super() 依赖继承
class Hero:
def __init__(self, name, life_value, aggressivity):
self.name = name
self.life_value = life_value
self.aggressivity = aggressivity def attck(self,enemy):
enemy.life_value -= self.aggressivity class Garen(Hero): def __init__(self, name, life_value, aggressivity, weapon):
# Hero.__init__(self,name, life_value, aggressivity) # 指名道姓的调用父类中的方法.
# super(Garen,self).__init__(name,life_value,aggressivity)
super().__init__(name,life_value,aggressivity) # 简写
self.weapon = weapon def attck(self,enemy):
# Hero.attck(self,enemy) # 指名道姓的调用父类中的方法.
# super(Garen,self).attck(enemy) # super方法,括号里的Garen的位置是子类的名称,self是生成对象的名称.后面是调用的方法.
super().attck(enemy) # 在py3中,可以简写成这样.
print("in Garen class") class Riven(Hero):
pass g1 = Garen("草丛伦", 100, 50,"黑切")
r1 = Riven("兔女郎瑞文", 80,50)
g1.attck(r1)
print(r1.life_value) print(g1.__dict__) # 查看g1的dict中,已经有了黑切.

super方法

 class A:
def f1(self):
print("from A")
super().f1() #在这里调用super().f1()的时候.基于的是C这个类的mro列表进行查找的.并不是说,在A类中调用super,就是在A类中,查找A的父类中的f1方法 class B:
def f1(self):
print("from B") class C(A,B):
pass print(C.mro())
i = C()
i.f1() # 查找f1的是,都是基于对象i来进行查找的.如果i里没有f1方法.那么就去它的类中查找,如果类中没有,就去类所继承的父类中按照mro列表查找.

super继承验证

组合

软件重用的重要方式除了继承之外还有另外一种方式,即:组合

组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合.

组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,

1.继承的方式

通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

2.组合的方式

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

 class People:
"""定义人类"""
school = "luffycity"
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex =sex class Teacher(People):
"""定义一个人教师类"""
def __init__(self, name, age, sex, level, salary):
super().__init__(name, age, sex)
self.level = level
self.salary = salary def teach(self):
print("%s is teaching" % self.name) class Students(People):
"""定义一个学生类"""
def __init__(self, name, age, sex, grade):
super().__init__(name, age, sex)
self.grade = grade def learn(self):
print("%s is learning" % self.name) class Course:
"""定义一个课程类"""
def __init__(self, course_name, course_price, course_period):
self.course_name = course_name
self.course_price = course_price
self.course_period = course_period def tell_info(self):
print("课程名:%s, 课程价格:%s, 课程周期:%s" % (self.course_name, self.course_price, self.course_period)) class Bron_date:
"""定义一个生日类"""
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day
def tell_info(self):
print("生日:%s年%s月%s日" % (self.year, self.mon, self.day)) # t1 = Teacher("alex", 22, "男", "一级", 100000)
#生成一个stu1的学生对象
stu1 = Students("杰克", 18, "男", "python全栈开发")
#生成一个python的课程对象
python = Course("python", 8999, "6mons")
# 把python对象赋给stu1.course.学生stu1有课程.这里就是组合
stu1.course = python
#输入sut1的课程信息

组合实例

抽象类

如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

作用:

抽象类规范了子类的属性或者方法的定义规范.

抽取子类相似的属性或特征,组成一个新的类.就叫抽象类,抽象类只能被继承,不能被实例化.

  抽象类,归一化
import abc
# 生成一个抽象类,需要借助abc这个模块.
class Animal(metaclass=abc.ABCMeta): # 抽取子类相似的属性或特征,组成一个新的类.就叫抽象类,抽象类只能被继承,不能被实例化.
@abc.abstractmethod #加上这个装饰器,子类在继承抽象类的时候,必须有run,eat的方法.
def run(self):
pass
@abc.abstractmethod
def eat(self):
pass class People(Animal):
def run(self):
print("people is running.")
def eat(self):
print("people is eating") class Dog(Animal):
def run(self):
print("dog is running") def eat(self):
print("dog is eating")
class Pig(Animal):
def run(self):
print("pig is running") # def eat(self): # 如果我们注释掉这行,就无法正常实例化一个对象,因为缺少一个eat方法.
# print("pig is eating") p1 = People()
d1 = Dog()
p1 = Pig() p1.run()
d1.run()
p1.run()

生成抽象类