面向编程(二)继承
一.基础
1 class Garen: 2 camp='Demacia' 3 n=0 4 hobby=[] #类的变量一般定义成不可变的 5 def __init__(self,nickname,aggressivity=58,life_value=455): 6 self.nickname=nickname #为自己的盖伦起了个别名 7 self.aggressivity=aggressivity 8 self.life_value=life_value 9 Garen.n+=1 #类.n 对象每产生一个名字(统计实例化次数) 10 #self.hobby=[] 11 def attack(self,enemy): 12 enemy.life_value-=self.aggressivity 13 14 g1=Garen('草丛伦') 15 g2=Garen('草丛伦2') 16 g3=Garen('草丛伦3') 17 print(g1.hobby,id(g1.hobby)) 18 print(g2.hobby,id(g2.hobby)) 19 print(g3.hobby,id(g3.hobby)) 20 print(g1.n) # 21 print(g3.n) 22 23 24 25 26 27 [] 13837768 #指向同一个列表,同一个内存地址 28 [] 13837768 29 [] 13837768 30 3 31 3
1 g1.hobby.append('g1 hobby') 2 g2.hobby.append('g2 hobby') 3 g3.hobby.append('g3 hobby') 4 print(g1.hobby) 5 g1.camp='12123' 6 print(g1.camp) 7 8 9 10 ['g1 hobby', 'g2 hobby', 'g3 hobby'] #可变类型 11 12123 #不可变类型
1 class Garen: 2 camp='Demacia' 3 n=0 4 #hobby=[] #类的变量一般定义成不可变的 5 def __init__(self,nickname,aggressivity=58,life_value=455): 6 self.nickname=nickname #为自己的盖伦起了个别名 7 self.aggressivity=aggressivity 8 self.life_value=life_value 9 Garen.n+=1 #类.n 对象每产生一个名字(统计实例化次数) 10 self.hobby=[] #定义在自己里面,别的实例进不来 11 def attack(self,enemy): 12 enemy.life_value-=self.aggressivity 13 g1=Garen('草丛伦') 14 g2=Garen('草丛伦2') 15 g3=Garen('草丛伦3') 16 17 18 g1.hobby.append('g1 hobby') 19 g2.hobby.append('g2 hobby') 20 g3.hobby.append('g3 hobby') 21 print(g1.hobby) 22 23 24 25 26 27 ['g1 hobby']
1 class Garen: 2 camp='Demacia' 3 n=0 4 #hobby=[] #类的变量一般定义成不可变的 5 def __init__(self,nickname,aggressivity=58,life_value=455): 6 self.nickname=nickname #为自己的盖伦起了个别名 7 self.aggressivity=aggressivity 8 self.life_value=life_value 9 Garen.n+=1 #类.n 对象每产生一个名字(统计实例化次数) 10 self.hobby=[] #定义在自己里面,别的实例进不来 11 def attack(self,enemy): 12 print('=====>') 13 enemy.life_value-=self.aggressivity 14 15 g1=Garen('草丛伦') 16 g2=Garen('草丛伦2') 17 # print(g1.hobby,id(g1.hobby)) 18 # print(g2.hobby,id(g2.hobby)) 19 # print(g3.hobby,id(g3.hobby)) 20 # print(g1.n) # 21 # print(g3.n) 22 print(g1.attack) 23 print(Garen.attack) 24 g1.attack(g2) #绑定方法指向函数的功能,就是绑定到每个对象身上的 25 #对象调绑定方法操作的就是对象自己,Garen.attack(g1,g2) g2为位置参数 26 #其实就相当于Gaven.attack(g1,g2) 27 #区别:可以把对象自己当成参数传进去
二.继承
1.什么是继承
继承是一种创建新的类的方法,在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类。
分为: 单继承和多继承
1 class ParentClass1: #定义父类 2 pass 3 class ParentClass2: #定义父类 4 pass 5 class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass 6 pass 7 class SubClass2(ParentClass1,ParentClass2): #多继承,用逗号分隔开多个继承的类 8 pass 73 74 print(SubClass1.__bases__) 75 print(SubClass2.__bases__) 76 print(ParentClass1.__bases__) #python的类默认继承object类,object是所有python类的基类,它提供一些常见方法如(_str_)实现 77 78 79 80 (<class '__main__.ParentClass1'>,) 81 (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>) 82 (<class 'object'>,)
抽象即抽取类似或者说比较像的部分。
抽象分成两个层次:
1.将奥巴马和梅西这俩对象比较像的部分抽取成类;
2.将人,猪,狗这三个类比较像的部分抽取成父类。
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
1 class Hero: 2 def __init__(self,nickname,aggressivity,life_value): 3 self.nickname=nickname 4 self.aggressivity=aggressivity 5 self.life_value=life_value 6 7 def move_forward(self): 8 print('%s move forward' %self.nickname) 9 10 def move_backward(self): 11 print('%s move backward' %self.nickname) 12 13 def move_left(self): 14 print('%s move forward' %self.nickname) 15 16 def move_right(self): 17 print('%s move forward' %self.nickname) 18 19 def attack(self,enemy): 20 enemy.life_value-=self.aggressivity 21 class Garen(Hero): 22 pass 23 24 class Riven(Hero): 25 pass 26 27 g1=Garen('草丛伦',100,300) 28 r1=Riven('锐雯雯',57,200) 29 30 print(g1.life_value) 31 r1.attack(g1) 32 print(g1.life_value) 33 34 ''' 35 运行结果 36 300 37 243 38 '''
2.派生
如果在子类中定义与父类相同的,走子类中的。也可以定义一个新的。
1 class Hero: 2 def __init__(self,nickname, 3 aggressivity, 4 life_value): 5 self.nickname = nickname 6 self.aggressivity = aggressivity 7 self.life_value = life_value 8 9 def attack(self,enemy): 10 enemy.life_value -= self.aggressivity 11 12 13 class Garen(Hero): 14 camp='Demacia' 15 def attack(self,enemy): 16 print('from garen attack') #如果在子类中定义与父类相同的,走子类中的 17 def fire(self): 18 print('%s is fireing' %self.nickname) 19 20 class Riven(Hero): 21 camp='Noxus' 22 23 g1=Garen('garen',18,200) 24 r1=Riven('rivren',18,200) 25 g1.attack(r1) 26 print(g1.camp) 27 print(r1.camp)
1.重用
1 class Hero: 2 def __init__(self,nickname, 3 aggressivity, 4 life_value): 5 self.nickname = nickname 6 self.aggressivity = aggressivity 7 self.life_value = life_value 8 9 def attack(self,enemy): 5. 10 print('Hero attack') 11 enemy.life_value -= self.aggressivity 12 class Garen(Hero): 13 camp='Demacia' 14 def attack(self,enemy): # 3.指向类的函数 self=g1,enemy=r1 15 Hero.attack(self,enemy) #重用父类的 4 16 print('from garen attack') #如果在子类中定义与父类相同的,走子类中的 17 def fire(self): 18 print('%s is fireing' %self.nickname) 19 20 class Riven(Hero): 21 camp='Noxus' 22 23 g1=Garen('garen',18,200) # 1.g1的名称空间 24 r1=Riven('rivren',18,200) 25 g1.attack(r1) # 2.g1的绑定方法 不用传参数,实际传的g1和r1 26 27 28 Hero attack 29 from garen attack
1 class Hero: 2 def __init__(self,nickname, 3 aggressivity, 4 life_value): 5 self.nickname = nickname 6 self.aggressivity = aggressivity 7 self.life_value = life_value 8 9 def attack(self,enemy): 10 print('Hero attack') 11 enemy.life_value -= self.aggressivity 12 class Garen(Hero): 13 camp='Demacia' 14 def __init__(self,nickname,aggressivity,life_value,script): ## 15 Hero.__init__(self,nickname,aggressivity,life_value) ##调用父类功能 16 self.script = script #新属性 17 def attack(self,enemy): #self=g1,enemy=r1 #在这里定义新的attack,不再使用父类的attack,且不会影响父类 18 Hero.attack(self,enemy) #重用父类的 19 print('from garen attack') #如果在子类中定义与父类相同的,走子类中的 20 def fire(self): 21 print('%s is fireing' %self.nickname) 22 23 class Riven(Hero): 24 camp='Noxus' 25 26 g1=Garen('garen',18,200,'人在塔下') #Garen.__init__(g1,'garen',18,200,'人在塔下')
2.组合
1 class Teacher: 2 def __init__(self,name,sex,course): 3 self.name=name 4 self.sex=sex 5 self.course=course 6 7 class Student: 8 def __init__(self,name,sex,course): 9 self.name=name 10 self.sex=sex 11 self.course=course 12 13 class Course: 14 def __init__(self,name,price,period): 15 self.name=name 16 self.price=price 17 self.period=period 18 19 python_obj=Course('python',15800,'7m') 20 t1=Teacher('egon','male',python_obj) 21 s1=Student('cobila','male',python_obj)
print(s1.course.name)
print(t1.course.name)
继承: 类与类之间是的关系,完成代码重用 (人和狗都是动物)
组合:类与类之间有的关系,(老师,学生与生日 老师,学生与课程 学生与分数)
3.接口与归一化设计
继承
一::继承基类的方法,并做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类定义了一些接口名(就是函数名)
继承的第二种含义非常重要,它又叫接口继承。接口继承实质上是要求做一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理时限了特定接口的所有对象——这在程序设计上,叫做归一化。
1.主动抛出异常
class Animal: def run(self): raise AttributeError('子类必须实现这个方法') def speak(self): raise AttributeError('子类必须实现这个方法') class People(Animal): pass # def run(self): # print('人正在走') # def speak(self): # print('说话') peo1=People() peo1.run() raise AttributeError('子类必须实现这个方法') AttributeError: 子类必须实现这个方法
2.抽象类
本质还是类,与普通类额外的特点是:加了装饰器的函数,子类必须实现他们。
普通类除了raise抛出异常没有其他方法限制子类必须实现
1 import abc 2 class Animal(metaclass=abc.ABCMeta): 3 @abc.abstractmethod #必须被子类实现run 4 def run(self): 5 pass 6 @abc.abstractmethod #必须被子类实现speak 7 def speak(self): 8 pass 9 10 11 class People(Animal): 12 def run(self): 13 pass 14 15 def speak(self): 16 pass 17 peo1=People() #做实例化时会报错