1.继承有三个特性:封装、继承、多态
下面来看一个继承的实例,这个实例很好理解,这里不多做解释了。
class People:
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print("%s is eating..." % self.name)
def talk(self):
print("%s is talkig..." % self.name)
def sleep(self):
print("%s is sleeping..." % self.name)
#继承
class Man(People):
pass
def run(self):
print("%s is running..."% self.name)
def sleep(self):
People.sleep(self) #调用父类的sleep方法
print("man is sleeping...")
class Woman(People):
def get_birth(self):
print("%s is born a baby..." % self.name)
m1=Man("wu",18) #实例化
m1.eat()
m1.run()
m1.sleep()
w1=Woman("Chen",22)
w1.get_birth()
w1.run() #w1不能调用 man的方法,所以报错
2.我们以上面的男人、女人的例子接着来说继承。
(1)如果在初始化一个男人的时候想多传一个属性,女人不需要这个属性,这时不能在People的构造函数中添加,需要在Man中初始化:
这时父类的所有参数在子类Man中要全部重写一遍,然后加入子类需要的属性:
class Man(People,Relation): #多继承;执行顺序默认为从左到右
def __init__(self,name,age,money): #name,age在父类中实现,money在子类中实现;要把父类的参数写一遍,否则会覆盖
People.__init__(self,name,age) #调用父类的构造方法,经典类写法
self.money = money
print("%s 一出生就有%s money" %(self.name,self.money))
(2)还有一种调用父类构造函数的方法:
super(Man, self).__init__(name,age) #与People.__init__(self,name,age)效果一样,新式类的写法
super(Man, self).__init__(name,age)方法与 People.__init__(self,name,age) 作用是一样的,super是新式类的写法,
(3)那么这时我们也需要将类People改为新式类的写法:
#class People: 经典类 class People(object): #新式类,多继承的方法变了
3.多继承方法:
(1)我们新加一个类Relation:
class Relation(object): def make_friends(self,obj): print("%s is making friends with %s " %(self.name,obj.name))
这时使Woman跟Man继承People跟Relation这两个类:
#继承 class Man(People,Relation): #多继承;执行顺序默认为从左到右 def __init__(self,name,age,money): #name,age在父类中实现,money在子类中实现;要把父类的参数写一遍,否则会覆盖 super(Man, self).__init__(name,age) #与People.__init__(self,name,age)效果一样,新式类的写法 self.money = money print("%s 一出生就有%s money" %(self.name,self.money)) def run(self): print("%s is running..."% self.name) def sleep(self): People.sleep(self) #调用父类的sleep方法 print("man is sleeping...") class Woman(People,Relation): def get_birth(self): print("%s is born a baby..." % self.name)
实例化两个对象:
m1=Man("wu",18,100) w1=Woman("Chen",22) m1.make_friends(w1)
输出结果为:
wu 一出生就有100 money
wu is making friends with Chen
多继承中,执行顺序默认为从左到右
(2)我们在类People中新增一个默认朋友列表:
class People(object): #新式类,多继承的方法变了
def __init__(self,name,age):
self.name=name
self.age=age
self.friends=[]
在Relation中将people与relation增加联系,在friend增加obj:
class Relation(object): def make_friends(self,obj): print("%s is making friends with %s " %(self.name,obj.name)) self.friends.append(obj) #参数为obj,保存的为内存地址;
如果参数为obj.name,是字符串,只是将w1的名字传入进去,如果修改,打印的结果不会改变
我们在实例化以后也可以通过打印结果看出来:
m1=Man("wu",18,100) w1=Woman("Chen",22) m1.make_friends(w1) print(m1.friends) #打印输出的为内存地址 print(m1.friends[0].name)#打印输出的为Chen w1.name="wang" print(m1.friends) #打印输出的为内存地址;修改名字后,内存地址不会变化 print(m1.friends[0].name) #父类Relation中,self.friends.append(obj),将w1的内存地址传入,
所以修改了w1的名字后,这里面存的名字也发生变化
打印结果为:
wu 一出生就有100 money wu is making friends with Chen [<__main__.Woman object at 0x02AAEED0>] Chen [<__main__.Woman object at 0x02AAEED0>] wang
4.经典类与新式类的继承顺序:
现在有这样一个例子:
class A: def __init__(self): print("A") class B(A): pass # def __init__(self): # print("B") class C(A): pass # def __init__(self): # print("C") class D(B,C): pass # def __init__(self): # print("D") obj = D()
这段程序中B继承A,C继承A,D继承B跟C。
(1)我们先不考虑A,先考虑B、C、D这三个类。
图1
Class D(B,C):
pass
是多继承,继承顺序是从左到右,如果D中没有构造函数,那么D先继承B中的构造函数,如果在B中有构造函数,那么尽管C中也有构造函数,D也不会继承C的构造函数,只会继承B的构造函数(B中的def __init__(self))
(2)我们这时加上A:会按照D->B->C->A的顺序来继承,如下图2所示(可以通过以上代码来验证):
图2
继承顺序是如下图3所示,D只会继承一个构造函数,只要它找到一个构造函数,它便不会再继续继承:
图3
我们又称图2的查找策略为广度优先:即把横向的策略先查完,在查找纵向的策略。
(3)由此我们便可知,还有一种深度优先策略:D->B->A->C,如下图4所示:
图4
(4)由此我们可知:
python2,经典类:按深度优先继承;新式类:按广度优先继承。
python3,经典类跟新式类均按广度优先继承。
5.是一个关于继承实例的讲解,是关于学校、学校成员、老师、学生的一个继承的实例。
class School(object): #object是基类 def __init__(self,name,addr): self.name=name self.addr=addr self.students=[] self.teacher=[] self.staffs=[] def enroll(self,stu_obj): #sut_obj 学生类的实例,enroll为注册 print("为%s办理注册手续"%stu_obj.name) self.students.append(stu_obj) def hire(self,staff_obj): self.staffs.append(staff_obj) print("雇用新员工%s"%staff_obj.name) class SchoolMember(object): def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def tell(self): #打印 pass class Teacher(SchoolMember): def __init__(self,name,age,sex,salary,course): super(Teacher,self).__init__(name,age,sex) self.salary=salary self.course=course def tell(self): print(''' ---info of Teacher:%s--- Name:%s Age:%s Sex:%s Salary:%s Course:%s '''%(self.name,self.name,self.age,self.sex,self.salary,self.course)) def teach(self): print("%s is teaching course [%s]"%(self.name,self.course)) class Student(SchoolMember): def __init__(self,name,age,sex,stu_id,grade): super(Student,self).__init__(name,age,sex) self.stu_id=stu_id self.grade=grade def tell(self): print(''' ---info of Student:%s--- Name:%s Age:%s Sex:%s Stu_id:%s grade:%s '''%(self.name,self.name,self.age,self.sex,self.stu_id,self.grade)) #交学费 def pay_tuition(self,amount): print("%s has paid tution for $%s"%(self.name,amount)) school=School("太原理工","大学城校区") t1=Teacher("Oldboy",56,"M",20000,"Linux") t2=Teacher("wu",18,"F",666,"PythonDevOps") s1=Student("chen",35,"M",1001,"PythonDevOps") s2=Student("徐",15,"M",1002,"Linux") t1.tell() s1.tell() school.hire(t1) school.enroll(s1) school.enroll(s2) print(school.students) print(school.staffs) school.staffs[0].teach() s1.pay_tuition(500) for stu in school.students: stu.pay_tuition(6000)
这个实例理解起来并不困难,是该节知识点的结合,所以不再解释。
6.多态实例讲解
(1)多态是一种接口的多种实现,允许将子类类型的指针赋值给父类类型的指针;
最重要的是接口重用,python不直接支持多态,但可以间接实现。
(2)现在有一个动物类:
A.按照我们熟悉的方法使先实例化,在调用talk方法
class Animal(object): def __init__(self, name): # Constructor of the class self.name = name def talk(self): pass class Cat(Animal): def talk(self): print('%s: 喵喵喵!' % self.name) class Dog(Animal): def talk(self): print('%s: 汪!汪!汪!' % self.name) d=Dog("chen") d.talk() c=Cat("xu") c.talk()
B.如果我们写一个关于animal_talk(obj): 的函数,将animal_talk作为一个统一的接口,如下,这时与上述输出结果一致的。
def animal_talk(obj): # 一个接口,多种形态;一个统一的接口 obj.talk() d=Dog("chen") c=Cat("xu") animal_talk(c) animal_talk(d)
C.现在我们将接口写入父类中:
class Animal(object): @staticmethod def animal_talk(obj): obj.talk() #将实现多态的接口写入父类Animal中 c=Cat("xu") d=Dog("chen") Animal.animal_talk(c) Animal.animal_talk(d)
这样便达到了接口重用的作用。
完