Python面向对象三大特征之继承

我们都知道Python面向对象编程有三大特征,继承,封装和多态,下面几篇问题,我们会分别讲述着几大特征。

今天说的是继承,如果有编程基础的人对这个词应该不会陌生,继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类,而子类会“”遗传”父类的属性(数据属性和函数属性),从而解决代码重用问题。

上面这段话就是继承的概念和使用继承所要达到的目的。

下面我们来看看具体代码案例,继续的大致写法就是

子类名(父类1,父类2,。。。)

Python是可以实现对继承的,有些编程语法是只能单继承。

class ParentClass:
    name= '父类'
    def __init__(self,size,color):
        self.size = size
        self.color = color

    def fun(self):
        print('我来自父类')


class SubClass(ParentClass):
        name = '子类'
        pass
#实例化对象
s1 = SubClass('30','red')

#{'size': '30', 'color': 'red'}  如果子类没有构造方法的话,子类属性会找到父类的构造方法,继承父类的数据属性
print(s1.__dict__)

#(<class 'object'>,)  python3中统一都是新式类,所以如果不加继承的父类,默认的父类是object类
print(ParentClass.__bases__)

#(<class '__main__.ParentClass'>,)  子类的父类
print(SubClass.__bases__)

# "我来自父类"   子类对象调用父类的方法
s1.fun()

#子类对象调用数据属性,会先在子类中找,如果找不到会去父类的作用域里面找
#这里子类里面定义了name属性所以结果是: 子类
#如果子类里面没有定name,结果就是:父类
print(s1.name)

这段是继承大致的用法,子类可以继承父类的数据属性和函数属性。下面我们说说使用继承的好处及代码重用和重写,组合的用法

代码重用

我们现在有2个类猫和狗,它们都是动物,那如果我们要描述猫和狗这2个类的话,我们会存在大量的重复代码,如下

class Cat:
    def cry(self):
        print('喵喵')
    def  eat(self):
        print('吃')
    def run(self):
        print('跑')
    def jump(self):
        print('跳')


class Dog:
    def cry(self):
        print('汪汪')
    def eat(self):
        print('吃')
    def run(self):
        print('跑')
    def jump(self):
        print('跳')

cat1 =  Cat()
dog1 = Dog()
cat1.cry()
dog1.cry()

上面2个类也许除了cry方法,其他的方法都是一样的,都猫和狗同意的动作,那像上面那样写,就会出现大量的重复代码,下面我们用继承来改写

class animal:
    def cry(self):
        print('动物叫')
    def eat(self):
        print('吃')
    def run(self):
        print('跑')
    def jump(self):
        print('跳')

class Cat(animal):
    def cry(self):
        print('喵喵')

class Dog(animal):
    def cry(self):
        print('汪汪')

cat1 =  Cat()
dog1 = Dog()
cat1.cry()  #喵喵
dog1.cry()  #汪汪
cat1.eat() #吃
dog1.eat() #吃

上面我们定义了一个animal的父类,把子类的相同部分放入父类,子类就可以用继承的方式来调用父类的函数属性或者说方法了,而不用再类里面再重复编码。

  1. 类的方法重写

其实上面的例子我们已经用到重写,就是父类定义了一个方法,但是子类和父类的方法实现不一样,要达到另外一个功能,比较上面

父类的cry方法时: ‘动物叫’

子类Cat的cry要实现:‘喵喵叫’

子类Dog的cry要实现:‘汪汪叫’

这种情况就要使用重写

class animal:
    def cry(self):
        print('动物叫')
    def eat(self):
        print('吃')
    def run(self):
        print('跑')
    def jump(self):
        print('跳')

class Cat(animal):
    def cry(self):
        print('喵喵')

class Dog(animal):
    def cry(self):
        print('汪汪')

cat1 =  Cat()
dog1 = Dog()
cat1.cry()  #喵喵  重写父类cry方法
dog1.cry()  #汪汪 重写父类cry方法
  1. 子类的方法派生,就是子类可以定义自己的方法
class animal:
   def cry(self):
       print('动物叫')
   def eat(self):
       print('吃')
   def run(self):
       print('跑')
   def jump(self):
       print('跳')

class Cat(animal):
   def cry(self):
       print('喵喵')
   def  swoop(self): #定义子类的方法
       print('飞扑')


cat1 =  Cat()
cat1.swoop()

4.类的组合,组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好.

class School:
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr


    def recruit(self):
        print('%s xxx计算机学校正在招生' %self.name)

class Course:
    def __init__(self,name,price,period,School):
        self.name=name
        self.price=price
        self.period=period
        self.school=School  #实现Course和School的组合
s1=School('xxx计算机学校','北京')
s2=School('xxx计算机学校','南京')
s3=School('xxx计算机学校','上海')

msg='''
1 xxx计算机学校 北京校区
2 xxx计算机学校 南京校区
3 xxx计算机学校 上海校区
'''
while True:
    print(msg)
    menu={
        '1':s1,
        '2':s2,
        '3':s3
    }
    choice=input('选择学校>>: ')
    school_obj=menu[choice]
    name=input('课程名>>: ')
    price=input('课程费用>>: ')
    period=input('课程周期>>: ')
    new_course=Course(name,price,period,school_obj)
    print('课程【%s】属于【%s】学校' %(new_course.name,new_course.school.name))  #实现Course和School的组合

5.Python实现接口

接口就是定义抽象函数,不做具体函数实现,起到规范子类的作用,让子类必须实现接口的抽象函数。接口提取了一群类共同的函数,可以把接口当做一个函数的集合。然后让子类去实现接口中的函数。这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。

归一化的好处在于:

  1. 归一化让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

  2. 归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合

下面上代码

import abc #利用abc模块实现抽象类
class Interface(metaclass=abc.ABCMeta):
    @abc.abstractclassmethod  #抽象方法,不做具体实现
    def test1(self):
        pass
    @abc.abstractclassmethod
    def test2(self):
        pass
class SubClass(Interface):
    def test1(self):
        print('实现抽象方法1')
    def test2(self):
        print('实现抽象方法2')

s1 = SubClass()

如果我们子类里面不实现具体的抽象函数,会报错

import abc #利用abc模块实现抽象类
class Interface(metaclass=abc.ABCMeta):
    @abc.abstractclassmethod  #抽象方法,不做具体实现
    def test1(self):
        pass
    @abc.abstractclassmethod
    def test2(self):
        pass
class SubClass(Interface):
    def test1(self):
        print('实现抽象方法1')
#不实现test2方法
s1 = SubClass()

报错信息:

Traceback (most recent call last):
File "C:/Users/aryin/Desktop/mysite2/继承.py", line 16, in <module>
s1 = SubClass()
TypeError: Can't instantiate abstract class SubClass with abstract methods test2

6.类继承的顺序,根据类的MRO属性

class A:
   def test(self):
       print('A')
class B(A):
   def test(self):
       print('B')

class C(A):
   def test(self):
       print('C')

class D(B):
   def test(self):
       print('D')

class E(C):
   def test(self):
       print('E')

class F(D,E):
   def test(self):
       print('F')
       
# (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
print(F.__mro__) 

类继承是是按照MRO属性里面的顺序去调用父类的属性

7.子类调用父类的方法,是通过super函数来实现的,在复杂的类继承关系中,super()的取值是按照上面的MRO里面的顺序来定的。

class animal:
    def __init__(self,name,type,size,color):
        self.name = name
        self.type = type
        self.size = size
        self.color = color
    def cry(self):
        print('动物叫')
    def eat(self):
        print('吃')

class Cat(animal):
    def __init__(self,name,type,size,color,age):
        super().__init__(name,type,size,color)  #调用父类的构造函数,这是super最常用的地方
        self.age = age
    def cry(self):
        super().cry()  #子类重新了父类的方法,但是同时又要实现父类中cry方法
        print('喵喵')

cat1 = Cat('毛球','波斯猫',10,'白色','5岁')

# 动物叫
# 喵喵
cat1.cry()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容