封装,继承,多态

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

封装

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

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

  • 目的:保护隐私

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

    属性私有化之前,用户的信息可以直接访问并修改
    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
  • 私有方法:在方法前加__例如: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)
    

你可能感兴趣的:(封装,继承,多态)