python学习第6周之继承跟多态

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)

 这样便达到了接口重用的作用。

 

 

posted @ 2019-09-07 17:27  凸凸yolotheway  阅读(209)  评论(0编辑  收藏  举报