Python基础(17)——类的继承和多态(附实例)

一、类的继承

        面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。

        在OOP(Object Oriented Programming,面向对象编程)程序设计中,当我们定义一个 class 的时候,可以从某个现有的 class 继承,通过继承创建的新类称为子类派生类(Subclass),被继承的类称为基类父类超类(Base class、Super class)。

1、继承语法

class 派生类名(基类名)
    ...

2、在python继承中的一些特点:

  • 如果子类需要父类的构造方法,就需显示调用父类的构造方法(即子类调用父类的构造方法重写子类的构造方法),或者不重写父类的构造方法;
  • 在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数;
  • Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

下面例子定义一个 Person 类,在 Person 类中定义属性变量 name 及 sex (姓名和性别);

定义一个方法 print_title(),当 sex 是 male 时,print man,当sex 是female时,print woman;

而我们编写 Child 类,完全可以继承 Person 类(Child 就是 Person);使用 class subclass_name(baseclass_name) 来表示继承。

代码如下:

class Person(object):
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
        
    def print_title(self):
        if self.sex == "male":
            print("man")
        elif self.sex == "female":
            print("woman")

class Child(Person):                            #Child 继承 Person
    pass
                         
Peter = Person("Peter","male")                  #创建父类Person的一个对象Peter
May = Child("May","female")                     #创建子类Child的一个对象May  
 
print(May.name,May.sex,Peter.name,Peter.sex)    #子类继承父类方法及属性
May.print_title()                               #调用父类的方法
Peter.print_title()                             #调用父类的方法

        由此可见继承的最大好处是子类获得了父类的全部属性及功能。如上 Child 类可以直接使用父类的 print_title() 方法,实例化Child的时候,子类继承了父类的构造函数,就需要提供父类 Person 要求的两个属性变量 name 及 sex。

   在继承关系中,如果一个实例的数据类型是某个子类,那它也可以被看做是父类(May 既是 Child 类又是 Person 类)。但是,反过来就不行(Peter 仅是 Person 类,而不是 Child 类)。

       Python 与其他语言不同点在于,当我们定义一个 class 的时候,相当于定义了一种数据类型。我们定义的数据类型和 Python 自带的数据类型,比如 str、list、dict 没什么两样。

因此,我们可以使用 issubclass() 或者 isinstance() 方法来检测上面所说的关系。

  • issubclass() — 布尔函数,用于检查类继承。判断一个类是否是另一个类的子类或者子孙类,语法:issubclass(sub,sup);
  • isinstance(obj, Class) — 布尔函数,用于检查实例类型。如果 obj 是 Class 类的实例对象或者是一个 Class 子类的实例对象,则返回 True。
print(isinstance(May,Child))         # May是Child类型,True
print(isinstance(May,Person))        # May是Person类型,True
print(isinstance(Peter,Child))       # Peter是Child类型,False
print(isinstance(Peter,Person))      # Peter是Person类型,True
print(issubclass(Child,Person))      # Child类继承Person类,True

  继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:  

二、类的多态

下面代码在子类 Child 中重写 print_title() 方法:若为 male,print boy;若为 female,print girl

class Person():
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
         
    def print_title(self):
        if self.sex == "male":
            print("man")
        elif self.sex == "female":
            print("woman")
 
class Child(Person):                #Child继承Person
    def print_title(self):          #修改父类的print_title()方法
        if self.sex == "male":
            print("boy")
        elif self.sex == "female":
            print("girl")
        
May = Child("May","female")        #创建Child的一个对象May
Peter = Person("Peter","male")     #创建Person的一个对象Peter
 
print(May.name,May.sex,Peter.name,Peter.sex)
May.print_title()                  #调用子类的print_title()方法
Peter.print_title()                #调用父类的print_title()方法

结果如下:
May female Peter male
girl
man

        观察上面代码及其运行结果可以看出,当子类和父类都存在相同的 print_title()方法时,子类的 print_title()覆盖了父类的 print_title(),在代码运行时,总是会调用子类的 print_title()。这样,我们就获得了继承的另一个好处:多态

  多态的好处就是,当我们需要传入更多的子类,例如新增 Teenagers、Grownups 等时,我们只需要继承 Person 类型就可以了,而print_title() 方法既可以不重写(即使用Person的),也可以重写一个继承类特有的,这就是多态的意思。

       对于一个变量,我们只需要知道它是 Person 类型,无需确切地知道它的子类型,就可以放心地调用 print_title()方法,而具体调用的 print_title()方法是作用 Child、Teenagers还是 Grownups 对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种 Person 的子类时,只要确保新方法编写正确,不用管原来的代码是如何调用的,这就是著名的 "开闭" 原则:

  •     对扩展开放(Open for extension):允许子类重写方法函数
  •     对修改封闭(Closed for modification):不需要重写方法,直接继承父类方法函数

三、子类重写构造函数

       子类可以没有构造函数,表示同父类构造一致;子类也可重写构造函数;下面代码在子类 Child 中新增两个属性变量:mother 和 father,我们可以构造如下(建议子类调用父类的构造方法,参见后续代码):

class Person():
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex

class Child(Person):                             #Child 继承 Person
    def __init__(self,name,sex,mother,father):   #子类Child重写构造方法
        self.name = name
        self.sex = sex
        self.mother = mother
        self.father = father

May = Child("May","female","April","June")
print(May.name,May.sex,May.mother,May.father) 

结果如下:
May female April June

        若父类构造函数包含很多属性,子类仅需新增1、2个,会有不少冗余的代码,所以子类可对父类的构造方法进行调用,以减少代码量,代码如下:

class Person(object):
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex

class Child(Person):                             #Child 继承 Person
    def __init__(self,name,sex,mother,father):   #子类调用父类构造方法重写子类的构造方法
        Person.__init__(self,name,sex)           #在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量
        self.mother = mother
        self.father = father

May = Child("May","female","April","June")
print(May.name,May.sex,May.mother,May.father)   

结果如下:
May female April June

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值