封装,继承,多态

面向对象的三大特征:封装、继承和多态

封装

  • 含义:在生活中封装就是将物品包裹起来,不让看到其内部,具有保护功能

    • 在程序设计中,封装是将类中的某些部分(某些属性和方法)隐藏起来,对象不能直接使用隐藏起来的属性和方法,具有保护功能
  • 总结:隐藏对象的属性和方法实现的细节,仅对外提供公共访问方式

  • 目的:保护隐私

  • 使用方式:将属性或者方法前面加上双下划线(我们也叫私有属性或者私有方法)

    属性私有化之前,用户的信息可以直接访问并修改
    class User:
        """用户类型"""
        def __init__(self,name,age):
            """用户姓名和年龄"""
            self.name = name
            self.age = age
        def __str__(self):
            return f"我叫{self.name},今年{self.age}岁"
    user = User("古印",18)
    # print(user)
    #访问用户的姓名
    # print(user.name)
    #可以修改用户的姓名
    user.name = "黄志"
    # print(user.name)
    user.age = -20
    print(user)
    
    #属性私有化之后,用户信息不可以被玩不访问或者修改
    class User:
        """用户类型"""
        def __init__(self,name,age):
            """用户姓名和年龄"""
            self.__name = name
            self.__age = age
        def __str__(self):
            return f"我叫{self.__name},今年{self.__age}岁"
    user = User("古印",18)
    # print(user)
    # 访问用户的姓名
    # print(user.__name) #不可以访问私有属性
    #修改用户的姓名其实是增加属性
    user.__name = "黄志" #新增了一个属性__name
    # print(user.__name)
    # print(user)
    
    #查看对象有哪些属性 __dict__
    # print(user.__dict__)
    
    #属性私有化之后,提供公共的访问方式和修改方式
    class User:
        """用户类型"""
        def __init__(self,name,age):
            """用户姓名和年龄"""
            self.__name = name
            self.__age = age
        def get_name(self): #命名规范:get_数据
            """访问姓名"""
            return self.__name
        def set_name(self,name):
            """修改姓名"""
            self.__name = name
        def get_age(self):
            """访问年龄"""
            return self.__age
        def set_age(self,age):
            """修改年龄"""
            if 0<age<=100:
                self.__age = age
            else:
                print("年龄不符合要求")
        def __str__(self):
            return f"我叫{self.__name},今年{self.__age}岁"
    user = User("古印",18)
    print(user)
    print(user.get_name(),user.get_age())
    user.set_name("小古")
    user.set_age(125)
    print(user)
    
  • 私有方法:在方法前加__例如:send()-->__send()

    • 作用:在开发过程中保护核心代码,在类的外部不能使用(对象不能调用私有方法)

      class A:
          def __test1(self):
              print("--in test1--")
      
          def test2(self):
              self.__test1()
              print("--in test2--")
      a = A()
      # a.__test1() #对象不能调用私有方法
      a.test2()
      
  • 私有化封装后的限制

    • 1.类中 可以访问
    • 2.类外/对象外 不可以访问
    • 3.子类/子类对象 不可以访问
    • 注意:
      • 1.在python中实现封装操作,不是通过权限限制,而是通过改名策略实现的
      • 2.可以使用__dict__()查看属性(包括私有属性),在类的内部使用私有属性,python内部会自动转化为 _类名__属性名
      • 3.在类的外部不能给对象添加或者修改私有属性,因为不能转换为 _类名__属性名

继承

  • 含义:让类与类直接产生父子关系,子类可以拥有父类的属性和方法(私有属性和私有方法无法继承)

  • 父类和子类

    • 父类:用于被继承的类,称为父类,也叫基类,或者超类
    • 子类:继承其他类的类,称为子类,也叫派生类
  • 继承的作用:可以提高代码的重用率

  • 继承语法:子类声明后面的括号中添加类型,添加的类型就是当前子类继承的父类,有了继承声明,子类就包含了父类的公共属性和方法

    class Vehicle:
        """交通工具类"""
        def __init__(self,brand):
            self.brand = brand
        def move(self):
            # """移动的方法"""
            print(f"{self.brand}开始移动")
    class Plane(Vehicle):
        """飞机类型"""
        pass
    # plane = Plane("波音747")
    # plane.move()
    
  • 方法的覆盖

    • 子类方法中定义了和父类相同的方法,我们叫做方法的覆盖(派生方法)。实例对象调用此方法的时候就会调用自己类中的方法
    class Vehicle:
        """交通工具类"""
        def __init__(self,brand):
            self.brand = brand
        def move(self):
            # """移动的方法"""
            print(f"{self.brand}开始移动")
    class Plane(Vehicle):
        """飞机类型"""
        def move(self):
            print("飞机在快速移动中")
    plane = Plane("波音747")
    plane.move()
    
    • 查看继承的父类

      • 格式:类名.__base__

      • 注意:

        • 1.python3中,如果一个类没有继承任何类,默认继承object类,新式类

        • 2.object类,是python中的祖先,所有类都是从object类中继承下来

        • 3.继承可以隔代

  • super()方法

    • 子类和父类有相同的方法,如果子类想调用父类相同的方法,可以使用super()方法

      1.父类名.方法名(self)

      2.2.super(当前类名,self).方法名()

      3.super(当前类名,self).方法名()

    坦克大战
    敌方坦克和我方法坦克开火方法类似但又不完全相同
    把相同属性和方法定义在基本坦克类中,我方坦克和敌方坦克继承基本坦克类
    把不同的代码写在自己的开火方法中,调用自己开火方法中再调用父类方法
    class BaseTank:
        """基本坦克类"""
        def fire(self):
            """开火的方法"""
            print("坦克开火了,发射子弹(15行代码)")
    
    class HeroTank(BaseTank):
        """英雄坦克类"""
        def fire(self):
            """子类中有自己的开火技能"""
            print("英雄坦克,按下空格键,发射子弹(5行代码)")
            #调用父类中发射子弹的代码
            # BaseTank.fire(self)         #1.父类名.方法名(self)
            # super(HeroTank, self).fire()  #2.super(当前类名,self).方法名()
            super().fire()                #3.super().方法名()
    class EnemyTank(BaseTank):
        """敌方坦克"""
        def fire(self):
            """子类中有自己的开火技能"""
            print("敌方坦克,随机发射子弹(7行代码)")
            # 调用父类中发射子弹的代码
            BaseTank.fire(self)
    
    hero_tank = HeroTank()
    hero_tank.fire()
    enemy_tank = EnemyTank()
    enemy_tank.fire()
    

    多继承

    • 一个子类可以继承多个父类,就是多继承,并且拥有父类的属性和方法

    • 如果子列和父类有相同的方法,就会调用子类的方法

      • 思考:如果不同的父类存在着相同的方法,子类对象调用父类的时候,会调用那个方法?
      class Dog:
          """狗的类别"""
          def eat(self):
              """吃的方法"""
              print("吃粑粑")
      class God:
          """神仙的类别"""
          # def eat(self):
          #     print("吃蟠桃")
          pass
      class Xtq(God,Dog):
          """神仙狗类"""
          pass
      # xtq = Xtq()
      # xtq.eat()
      # print(Xtq.mro())
      # print(Xtq.__mro__)
      
      • python会根据MRO方法解析顺序列表进行查找
      • python2.3起开始C3算法,定义类需要继承的object,称之为新式类,广度优先搜索
      • MRO列表遵循一下三条原则
        • 1.子类会先于父类被检查
        • 2.多个父类会根据他们在列表中的顺序别检查
        • 3.如果对下一个类存在两个合法选择,选择第一个父类
  • __init--()方法

    • 子类继承父类,如果子类不复写父类的__init--()方法,创建子类对象的时候会自动调用父类的__init--()方法

    • 子类继承父类,如果复写了父类的__init--()方法,创建子类对象的时候不会再调用父类的__init--()方法

    • 注意:如果复写了父类的__init--()方法,需要调用的父类__init--()方法,会存在隐患,如果父类的初始化方法有参宿,子类初始化无参数,子类调用父类方法就会报错,所以注意传参问题

      #猫类和其他宠物类相比,有自己的昵称属性
      class Pet:
          def __init__(self,age):
              self.age = age
          def __str__(self):
              return str(self.age)
      class Cat(Pet):
          """猫类"""
          def __init__(self,nickname,age):
              super(Cat, self).__init__(age)
              self.nickname = nickname
          def __str__(self):
              return f"{self.nickname},{self.age}"
      cat = Cat("tom",3)
      print(cat)
      
    • 继承的好处:提高代码的复用性,可以提升项目功能的扩展性

  • 综合案例:

    • 宠物类

      • 属性:名字,健康值
      • 方法:恢复健康
    • 医院类

      • 属性:医院名称
      • 方法:治疗宠物(调用宠物恢复健康的方法)
    • 狗类:继承宠物类

    • 猫类:继承宠物类

      import time
      class Pet:
          """宠物类"""
          def __init__(self,name,health):
              self.name = name
              self.health = health #小于60生病
      
          def recovery(self):
              """恢复健康的行为"""
              while self.health<60:
                  self.health+=5
                  print(f"{self.name}正在快速恢复中。。。")
                  time.sleep(1)
          def __str__(self):
              return f"{self.name}的健康值是:{self.health}"
      
      class Hospital:
          def __init__(self,name):
              self.name = name
          def care(self,pet):
              if isinstance(pet,Pet):
                  print(f"开始治疗{pet.name}")
                  pet.recovery()
              else:
                  print("宠物医院只接收宠物")
      class Dog(Pet):
          pass
      class Cat(Pet):
          pass
      
      class Peron:
          def __init__(self,name,health):
              self.name = name
              self.health = health
          def recovery(self):
              while self.health < 60:
                  self.health += 5
                  print(f"{self.name}正在快速恢复中。。。")
                  time.sleep(1)
      
      cat1 = Cat("tom",40)
      hospital = Hospital("南沙中心医院")
      # hospital.care(cat1)
      # print(cat1)
      per1 = Peron("小古",45)
      hospital.care(per1)
      

    抽象类

    • 1.从实现方式看,抽象类和普通类的不同之处在于:抽象类中有抽象方法,给该类不能被实例化,只能被继承,而且子类必须实现抽象方法
    • 2.抽象类中可以定义普通方法
    • 3.使用抽象类一般是单继承

    多态

    • 1.封装:屏蔽实现细节,但对外提供公共访问方式,将功能封装成一个整体,提供简单的调用方式

    • 2.继承:让类和类之间产生父子关系,子类可以拥有父类的属性和方式

    • 3.多态:可以让某个类实现多重形态

      多态的三个条件

      • 1.必须存在继承关系
      • 2.重写目标方法
      • 3.使用子类对象调用父类方法
      定义人类:可以跳舞,可以玩,在玩的过程中跳舞
      #实现多态:老年人跳广场舞
      class Person:
          """人的类型"""
          def dance(self):
              print("跳舞")
      
          def play(self): #old
              print("开始玩")
              self.dance() #old.dance()
      class OldMan(Person):
          """老年人类别"""
          def dance(self):
              print("跳广场舞")
      
      # per1 = Person()
      # per1.play()
      old= OldMan()
      old.play()
      
  • 用户注册案例

    • 网站可以注册,注册有默认的注册方式
    • 分析
      • 网站类:
        • 方法:注册方法,调用默认的设备发送验证码
      • 设备类
        • 方法:生成验证码并发送
    class Website:
        """网站类型"""
        def register(self,device):
            print("开始注册。。")
            #调用设备发送验证码的方法
            device.send("6666")
            input("验证码已发送,请输入:")
            print("注册成功")
    class Device:
        """设备类型"""
        def send(self,code):
            print("默认发送验证码:",code)
    #用户注册
    ws = Website()
    device = Device()
    #发起注册
    ws.register(device)
    
    • 实现多态,用不同的设备注册网站,就使用相应的设备发送验证码
    • 实现多态,用不同的设备注册网站,就使用相应的设备发送验证码
    class Website:
        """网站类型"""
        def register(self,device):
            print("开始注册。。")
            #调用设备发送验证码的方法
            device.send("6666")
            input("验证码已发送,请输入:")
            print("注册成功")
    class Device:
        """设备类型"""
        def send(self,code):
            print("默认发送验证码:",code)
    class Phone(Device):
        """手机注册"""
        def send(self,code):
            print("通过手机发送验证码:",code)
    class Email(Device):
        """邮箱注册"""
        def send(self,code):
            print("通过邮箱发送验证码:",code)
    # #用户注册
    ws = Website()
    # device = Device()
    # #发起注册
    phone = Phone()
    ws.register(phone)
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343