继承是一种是的关系,和组合对比,组合是一种有的关系,这两者都是解决代用重用问题的
继承
注意:继承不是遗传,在显示角度中,是通过对象抽象成类,再把这些类抽象成一个,就是父类。是自下而上的过程,在程序中是首先由父类,然后由类,之后才有对象,是自上而下的过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class classparent1: pass class classparent2: pass class useclass1(classparent1): pass class useclass2(classparent1,classparent2): pass print(useclass1.__bases__) print(useclass2.__bases__)
|
结果:
(,)
(, )
默认继承的是object类,Python3中都是新式类
类实例化
类实例化执行的时候首先从自己找,找不到从父类找。
继承与重用性
类中用的是父类的,不用重新写代码,实现了代码的复用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Hero: def __init__(self,nickname,aggressivity,life_value): self.nickname = nickname self.aggressivity = aggressivity self.life_value =life_value def attack(self,enemy): enemy.life_value -= self.aggressivity class Garen(Hero): pass class Riven(Hero): camp = 'Noxus' g1 = Garen('garen',18,200) r1 = Riven('garen',18,200)
|
派生
在子类中添加新的功能属性,派生首先是继承一个父类,定义一个新的,定义一个父类重名的,都会从子类自己的地方找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Hero: def __init__(self,nickname,aggressivity,life_value): self.nickname = nickname self.aggressivity = aggressivity self.life_value =life_value def attack(self,enemy): enemy.life_value -= self.aggressivity class Garen(Hero): camp = 'Ddemacia' def atatack(self,enemy): pass def fire(self): print('%s is fireing' %self.nickname) class Riven(Hero): camp = 'Noxus' g1 = Garen('garen',18,200) r1 = Riven('garen',18,200) g1.camp g1.atack(r1)
|
在派生中调用
子类继承了父类的方法,然后想进行修改,注意了是基于原有的基础上修改,那么就需要在子类中调用父类的方法
方法1
使用的是父类的的函数功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Hero: def __init__(self, nickname,aggressivity,life_value): self.nickname = nickname self.aggressivity = aggressivity self.life_value = life_value def attack(self, enemy): print('Hero attack') class Garen(Hero): camp = 'Demacia' def attack(self, enemy): Hero.attack(self,enemy) print('from garen attack') def fire(self): print('%s is firing' % self.nickname) class Riven(Hero): camp = 'Noxus' g1 = Garen('garen', 18, 200) r1 = Riven('rivren', 18, 200) g1.attack(r1)
|
对父类的init函数进行重用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Hero: def __init__(self, nickname, aggressivity, life_value): self.nickname = nickname self.aggressivity = aggressivity self.life_value = life_value def attack(self, enemy): print('Hero attack') enemy.life_value -= self.aggressivity class Garen(Hero): camp = 'Demacia' def __init__(self, nickname, aggressivity, life_value, script): Hero.__init__(self,nickname,aggressivity,life_value) self.script = script def attack(self, enemy): Hero.attack(self, enemy) print('from garen attack') def fire(self): print('%s is firing' % self.nickname) g1=Garen('garen',18,200,'人在塔在') print(g1.script)
|
方法2 Spper
python3 super
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class People: def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def walk(self): print("%s is walking"%self.name) class Chinese(People): country = 'china' def __init__(self,name,sex,age,language='Chinese'): super().__init__(name,sex,age) self.language = language def walk(self,x): super().walk() print('子类的x',x) c = Chinese('aaa','male',18) c.walk(123)
|
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
python2中的额super
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class People(object): def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def walk(self): print("%s is walking"%self.name) class Chinese(People): country = 'china' def __init__(self,name,sex,age,language='Chinese'): super(Chinese,self).__init__(name,sex,age) self.language = language c = Chinese('aaa','male',18) print(c.name,c.age,c.language)
|
组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
首先明确的是组合不是继承,是一种有的关系,是类与类之间的关系。
‘’’
不用组合的情况
‘’’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Teacher: def __init__(self,name,sex,course_name,course_price,course_peroid): self.name =name self.sex = sex self.course_name=course_name self.course_price = course_price self.course_peroid = course_peroid class Student: def __init__(self,name,sex,course_name,course_price,course_peroid): self.name = name self.sex = sex self.course_name = course_name self.course_price = course_price self.course_peroid = course_peroid t1 = Teacher('egon','male',) s1 = Student('cobile','name',) print(s1.course.name) print(t1.course.name)
|
使用类的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Course: def __init__(self,name,price,peroid): self.name = name self.price = price self.peroid = peroid class Teacher: def __init__(self,name,sex,course): self.name =name self.sex = sex self.course=course class Student: def __init__(self,name,sex,course): self.name = name self.sex = sex self.course = course python_obj = Course('python',15800,'7m') t1 = Teacher('egon','male',python_obj) s1 = Student('cobile','name',python_obj)
|
接口与归一化设计
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。
归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
抽象类
这里用抽象类实现了接口的方法,抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
抽象类用到了模块abc,装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import abc class Animal(metaclass=abc.ABCMeta): tag = '123' @abc.abstractclassmethod def run(self): pass @abc.abstractclassmethod def speak(self): pass class People(Animal): def run(self): pass def speak(self): pass peo1 = People() print(peo1.tag)
|
抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们