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)
这样便达到了接口重用的作用。
完