zoukankan      html  css  js  c++  java
  • 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)
    

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

  • 相关阅读:
    【HDOJ】2267 How Many People Can Survive
    【HDOJ】2268 How To Use The Car
    【HDOJ】2266 How Many Equations Can You Find
    【POJ】2278 DNA Sequence
    【ZOJ】3430 Detect the Virus
    【HDOJ】2896 病毒侵袭
    求奇数的乘积
    平方和与立方和
    求数列的和
    水仙花数
  • 原文地址:https://www.cnblogs.com/wuxiaoru/p/11481042.html
Copyright © 2011-2022 走看看