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)
    

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

  • 相关阅读:
    Java: Regular Expressions
    Java: Checked & Unchecked Exceptions
    二叉树的构建和层级打印
    [leetcode] 1032: Stream of Characters: Tries&AC自动机
    [leetcode] 1503: Previous Permutation With One Swap
    robot moving on the surface of a square
    killing rabbits
    Find the longest route with the smallest starting point
    [leetcode] Minimum Number of K Consecutive Bit Flips
    检测设备横屏 || 竖屏的状态
  • 原文地址:https://www.cnblogs.com/wuxiaoru/p/11481042.html
Copyright © 2011-2022 走看看