Python之面向对象继承和派生
什么是继承:
继承是一种创建新的类的方法。在Python中,新建的类可以继承自一个或多个父类。原始类称为基类或超类。
新建的类称为派生类或子类。
Python中类的继承分为单继承和多继承。
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1) #单继承,基类是ParentClass,派生是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类。 pass
print(SubClass1.__bases__) #查看继承的类。
注意:
如果没有指定基类。Python的类会默认继承object类。object是所有Python类的基类。他提供了一些常见方法。屁如:(__str__) 的实现。
继承与抽象(先抽象再继承):
抽象既抽取类似或者说比较像的部分。
抽象分为两个层次:
1,将Obama和George这两个对象比较像的部分抽取成类。
2,将人,猴,狗这三个类比较像的部分抽取成父类。
抽象最主要的作用是划分类别。(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方法去表达出抽象的结果。
抽象只是分析和设计的过程中,一个动作或者说一种技巧。通过抽象可以得到类。
多态:同一种事物的不同形态。人,狗都是动物。
继承与重用性:
重用性:将重复的功能写在父类里。在子类里继承即可。
1 ==========================第一部分 2 例如 3 4 猫可以:喵喵叫、吃、喝、拉、撒 5 6 狗可以:汪汪叫、吃、喝、拉、撒 7 8 如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,伪代码如下: 9 10 11 #猫和狗有大量相同的内容 12 class 猫: 13 14 def 喵喵叫(self): 15 print '喵喵叫' 16 17 def 吃(self): 18 # do something 19 20 def 喝(self): 21 # do something 22 23 def 拉(self): 24 # do something 25 26 def 撒(self): 27 # do something 28 29 class 狗: 30 31 def 汪汪叫(self): 32 print '喵喵叫' 33 34 def 吃(self): 35 # do something 36 37 def 喝(self): 38 # do something 39 40 def 拉(self): 41 # do something 42 43 def 撒(self): 44 # do something 45 46 47 48 ==========================第二部分 49 上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。如果使用 继承 的思想,如下实现: 50 51 动物:吃、喝、拉、撒 52 53 猫:喵喵叫(猫继承动物的功能) 54 55 狗:汪汪叫(狗继承动物的功能) 56 57 伪代码如下: 58 class 动物: 59 60 def 吃(self): 61 # do something 62 63 def 喝(self): 64 # do something 65 66 def 拉(self): 67 # do something 68 69 def 撒(self): 70 # do something 71 72 # 在类后面括号中写入另外一个类名,表示当前类继承另外一个类 73 class 猫(动物): 74 75 def 喵喵叫(self): 76 print '喵喵叫' 77 78 # 在类后面括号中写入另外一个类名,表示当前类继承另外一个类 79 class 狗(动物): 80 81 def 汪汪叫(self): 82 print '喵喵叫' 83 84 85 86 87 ==========================第三部分 88 #继承的代码实现 89 class Animal: 90 91 def eat(self): 92 print("%s 吃 " %self.name) 93 94 def drink(self): 95 print ("%s 喝 " %self.name) 96 97 def shit(self): 98 print ("%s 拉 " %self.name) 99 100 def pee(self): 101 print ("%s 撒 " %self.name) 102 103 104 class Cat(Animal): 105 106 def __init__(self, name): 107 self.name = name 108 self.breed = '猫' 109 110 def cry(self): 111 print('喵喵叫') 112 113 class Dog(Animal): 114 115 def __init__(self, name): 116 self.name = name 117 self.breed='狗' 118 119 def cry(self): 120 print('汪汪叫') 121 122 123 # ######### 执行 ######### 124 125 c1 = Cat('小白家的小黑猫') 126 c1.eat() 127 128 c2 = Cat('小黑的小白猫') 129 c2.drink() 130 131 d1 = Dog('胖子家的小瘦狗') 132 d1.eat() 133 134 使用继承来重用代码比较好的例子
在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时
我们不可能从头开始写一个类B,这就用到了类的继承的概念。
通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用
class Hero: def __init__(self,nickname,aggressivity,life_value): self.nickname=nickname self.aggressivity=aggressivity self.life_value=life_value def move_forward(self): print('%s move forward' %self.nickname) def move_backward(self): print('%s move backward' %self.nickname) def move_left(self): print('%s move forward' %self.nickname) def move_right(self): print('%s move forward' %self.nickname) def attack(self,enemy): enemy.life_value-=self.aggressivity class Garen(Hero): pass class Riven(Hero): pass g1=Garen('草丛伦',100,300) r1=Riven('锐雯雯',57,200) print(g1.life_value) r1.attack(g1) print(g1.life_value) ''' 运行结果 '''
提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,大大生了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.
注意:像g1.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。
重点!!!:再看属性查找
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() class Bar(Foo): def f1(self): print('Foo.f1') b=Bar() b.f2()
派生:
首先要继承一个父类,如果自己不定义自己的内容,那就从父类里拿。
如果在子类里定义和父类重名的东西,那么在调用时,以子类为准。
当然,也可以自己定义一个新的功能,父类没有的功能。
如何在子类里派生的方法里,重用父类的逻辑:
如何在子类的方法里调用父类的方法。
#派生 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): #self=g1,enemy=r1 # self.attack(enemy) #g1.attack() Hero.attack(self,enemy) #用父类里的attack,参数是Hero里的attack的参数。这里的self是g1,enemy是r1 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) # print(g1.camp) # print(r1.camp) # g1.fire()
在子类里,也定义init,这个init是和父类的init不冲突的。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
# print(Hero.__init__) # print(Hero.attack)
class Garen(Hero): camp = 'Demacia' def __init__(self, nickname, aggressivity, life_value, script): Hero.__init__(self,nickname,aggressivity,life_value) #调用父类的init方法, # self.nickname = nickname # self.aggressivity = aggressivity # self.life_value = life_value self.script = script #也可以自己加自己的init。
def attack(self, enemy): # self=g1,enemy=r1 # self.attack(enemy) #g1.attack() Hero.attack(self, enemy) print('from garen attack')
def fire(self): print('%s is firing' % self.nickname)
# g1=Garen('garen',18,200) #Garen.__init__(g1,'garen',18,200)
g1=Garen('garen',18,200,'人在塔在') #Garen.__init__(g1,'garen',18,200) print(g1.script)
组合:
多个类组合在一起。 解决代码的重用性。是一种类与类之间与的关系。
class Teacher: def __init__(self,name,sex,course,birth): self.name = name self.sex = sex self.course = course self.birth = birth class Student: def __init__(self,name,sex,course): self.name = name self.sex = sex self.course = course class Course: def __init__(self,name,price,peroid): self.name = name self.price = price self.peroid = peroid python_obj=Course('python',15800,'7m') t1=Teacher('egon','male',python_obj) s1=Student('cobila','male',python_obj) print(s1.course.name) print(t1.course.name) class Teacher: def __init__(self,name,sex,course_name,course_price,course_period): self.name=name self.sex=sex self.course_name=course_name self.course_price=course_price self.course_period=course_period class Student: def __init__(self,name,sex,course_name,course_price,course_period): self.name=name self.sex=sex self.course_name=course_name self.course_price=course_price self.course_period=course_period t1=Teacher('egon','male','python',15800,'7m') s1=Student('cobila','male','python',15800,'7m') print(s1.course.name) print(t1.course.name)
接口与归一化设计:
接口:接口是对外入口,Python是没有接口的概念的。所以Python只能用继承去模拟Java的接口。
class Animal: def run(self): #主动抛异常 raise AttributeError('子类必须实现这个方法') def speak(self): raise AttributeError('子类必须实现这个方法') class People(Animal): def run(self): print("Human is walk") def speak(self): print("man is tell") class Pig(Animal): def run(self): print('Pig is walking') def speak(self): print('Pig wow') peo1=People() # peo1.run() peo1.speak() # peo1=People() # pig1=Pig() # # peo1.run() # pig1.run() # class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。 # def read(self): #定接口函数read # pass # # def write(self): #定义接口函数write # pass # # # class Txt(Interface): #文本,具体实现read和write # def read(self): # print('文本数据的读取方法') # # def write(self): # print('文本数据的读取方法') # # class Sata(Interface): #磁盘,具体实现read和write # def read(self): # print('硬盘数据的读取方法') # # def write(self): # print('硬盘数据的读取方法') # # class Process(Interface): # def read(self): # print('进程数据的读取方法') # # def write(self): # print('进程数据的读取方法') # t1=Txt() # s1=Sata() # p1=Process() # t1.read() # t1.write() # s1.read() # s1.write() # p1.read() # p1.write()
主动抛异常:
class Animal: def run(self): #主动抛异常 raise AttributeError('子类必须实现这个方法') def speak(self): raise AttributeError('子类必须实现这个方法')
抽象类:
本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们
用abc模块。
所有子类,必须实现父类中加了装饰器函数的方法。否则无法实例。
import abc #抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们 class Animal(metaclass=abc.ABCMeta): tag='123123123123123' @abc.abstractmethod def run(self): pass @abc.abstractmethod def speak(self): pass class People(Animal): def run(self): pass def speak(self): pass peo1=People() print(peo1.tag)