Python面向对象三大特征

面向对象三大特征


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

    ​ 在程序设计中,封装(Encapsulation)是将类中某些部分(某些属性或者方法)隐藏起来,对象 不能直接使用隐藏起来的属性或者方法,具有保护功能

  • 总结:隐藏对象的属性和方法实现细节,仅对外提供公共访问方式

  • 目的:保护隐私

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

#属性私有化之前,用户信息可以直接访问并修改
class User:
    """用户类型"""
    def __init__(self,name,age):
        """用户姓名和年龄"""
        self.name = name
        self.age = age
    def __str__(self):
        """打印用户信息"""
        return f"我叫{self.name},今年{self.age}岁"

user = User("刘江",23)
# print(user)
#访问用户的姓名
# print(user.name)
#可以修改用户的姓名
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("刘江",23)
# print(user)
print(user.__name)

#修改用户的姓名和年龄
# user.__name = "梁国赞"
# user.__age = -20

# print(user.__name,user.__age)
# print(user) #还是原来的属性,并没有修改,而是增加属性
#属性私有化之后,提供公共的访问方式和修改方式
class User:
    """用户类型"""
    def __init__(self,name,age):
        """用户姓名和年龄"""
        self.__name = name
        self.__age = age

    def set_name(self,name):
        """修改姓名"""
        self.__name = name
    def get_name(self):
        """获取姓名"""
        return self.__name

    def set_age(self,age):
        """修改年龄"""
        if 0<age<=100:
            self.__age = age
        else:
            print("年龄不符合要求!")

    def get_age(self):
        """获取年龄"""
        return self.__age

    def __str__(self):
        """打印用户信息"""
        return f"我叫{self.__name},今年{self.__age}岁"
user = User("刘江",23)
# print(user)
# print(user.get_name())
# user.set_name("小江")
user.set_age(120) #设置不符合要求的年龄,无法修改
user.set_age(25) #设置符合要求的年龄,可以修改
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()
  • 案例:狗生一个崽儿,休一个月产假

    • 属性:孩子数量
    • 方法:生孩子,休产假,生孩子后自动调用休产假的方法
    class Dog:
        """狗的类型"""
        def __init__(self):
            self.__baby_count = 0 #定义狗崽儿的数量
    
        def birth(self):
            print("生了一个崽儿")
            self.__baby_count+=1
            #调用休产假的方法
            self.__holiday()
    
        def __holiday(self):
            print("休一个月产假!")
    
        def __str__(self):
            return f"孩子数量{self.__baby_count}"
    
    dog1= Dog()
    dog1.birth()
    print(dog1)
    # dog1.__holiday() #无法调用私有方法
    dog1.baby_count = 5  #无法修改狗崽儿的数量
    print(dog1)
    
  • 练习:打电话

    • 手机类
    • 方法:
      • 通话方法(私有方法)
      • 平台方法,检查话费余额,大于0调用通话方法
    class Phone:
        """手机类型"""
        def __call(self):
            """打电话方法"""
            print("可以打电话!")
    
        def platform(self,money):
            if money>0:
                self.__call()
            else:
                print("电话已欠费,请充值后再拨。。。")
    phone = Phone()
    # phone.__call() #私有方法不可以通过对象直接调用
    phone.platform(20)
    phone.platform(-10)
    
  • 私有化封装后的限制

    • 1.类中 可以访问
    • 2.类外/对象外 不可访问
    • 2.子类/子类对象 不可访问
    • 注意:
      • 1.在Python中实现的封装操作,不是通过权限限制而是通过改名策略实现的,名字变了找不到而已。
      • 2.可以使用__dict__()查看属性(包括私有属性),在类内部使用的私有属性,Python内部会自动进行转换成 _类名__属性名
      • 3.在类的外部不能给对象添加或者修改私有属性是因为不能转换为 _类名__属性名
class User:
    """用户类型"""
    def __init__(self,name,age):
        """用户姓名和年龄"""
        # self.name = name
        # self.age = age
        self.__name = name
        self.__age = age

    def __str__(self):
        """打印用户信息"""
        # return f"我叫{self.name},今年{self.age}岁"
        return f"我叫{self.__name},今年{self.__age}岁"
user = User("刘江",23)
# print(user)
#属性私有化之前,对象的属性如下
# print(user.__dict__) #{'name': '刘江', 'age': 23}
# user.name = "徐伟明" #可以修改


#属性私有化之后,对象的属性如下
print(user.__dict__) #{'_User__name': '刘江', '_User__age': 23}
# user.__name = "徐伟明" #只是增加属性
# print(user.__dict__)

user._User__name = "徐伟明"
print(user)
  • 思考:在类属性中添加私有属性,可以访问吗?可以修改吗?
继承
  • 含义:让类与类之间产生父子关系,子类可以拥有父类的属性和方法(私有属性和私有方法无法继承)

  • 父类和子类

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

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

    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) 继承可以隔代

        # 继承可以隔代
        class Animal:
            def eat(self):
                print("吃东西")
        
        class Dog(Animal):
            # def eat(self):
            #     print("吃骨头")
            pass
        
        class Hsq(Dog):
            pass
        
        hsq = Hsq()
        # hsq.eat()
        #查看继承的父类
        print(Hsq.__base__) #<class '__main__.Dog'>
        print(Dog.__base__) #<class '__main__.Animal'>
        print(Animal.__base__) #<class 'object'>
        
  • super()方法

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

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

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

      3.super().fire()

      #坦克大战
      #敌方坦克和我方坦克开火方法类似但又不完全相同
      #把相同属性和方法定义在基本坦克类中,我方和敌方坦克继承基本坦克类
      #把不同的代码写在自己的开火方法中,调用自己开发方法中再调用父类开火方法
      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().fire()
      
      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("吃蟠桃")
      
      class Xtq(God,Dog):
          """神仙狗类"""
          pass
      xtq = Xtq()
      xtq.eat() #吃蟠桃
      print(Xtq.mro()) #[<class '__main__.Xtq'>, <class '__main__.God'>, <class '__main__.Dog'>, <class 'object'>]
      
      • python 会根据MRO方法解析顺序列表进行查找
      • Python2.3起开始使用C3算法,定义类需要继承object,称之为新式类,广度优先搜索
      • MRO列表遵循以下三条准则
        • 1.子类会先于父类被检查
        • 2.多个父类会根据他们在列表中的顺序被检查
        • 3.如果对下一个类存在两个合法选择,选择第一个父类
    class A:
        def func(self):
            print("--A--")
    class B(A):
        def func(self):
            super(B, self).func()
            print("--B--")
    class C(A):
        def func(self):
            super(C, self).func()
            print("--C--")
    class D(B,C):
        def func(self):
            super(D, self).func()
            print("--D--")
    d = D() #继承顺序 D-->B-->C-->A
    d.func()
    print(D.mro())
    
  • __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}"
      cat1 = Cat("tom",3)
      print(cat1)
      
  • 继承的好处:可以提高代码的复用性,页可以提升项目功能的扩展性

综合案例:宠物就医,实现生病宠物去宠物医院治疗,最终康复的业务流程,具体逻辑

  • 宠物类

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

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

  • 猫类:继承宠物类

    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 Cat(Pet):
        """猫类"""
        pass
    
    class Dog(Pet):
        """狗类"""
        pass
    
    class Person:
        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 = Person("小张",30)
    # hospital.care(per1)
    
    #使用isinstance可以判断对象是否是类的实例
    # isinstance(对象,类)
    #可以判断数据类型
    a = [1]
    print(isinstance(a,list))
    print(isinstance(a,str))
    

    抽象类

    • 需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
    • 从实现角度看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接 口有点类似,但其实是不同的
    • 1.从实现角度来看,抽象类和普通类不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,而且子类必须实现抽象方法
    • 2.抽象类中可以定义普通方法
    • 3.抽象类也是定义规范
    • 4.使用抽象类一般是单继承
    #抽象类
    import abc
    class Person(metaclass=abc.ABCMeta):
        """这是一个抽象类,不能实例化"""
        @abc.abstractmethod
        def eat(self):
            """这是一个抽象方法,子类必须实现"""
            print("吃饭")
    
        def breath(self):
            """这是普通方法"""
            print("呼吸")
    
    class Student(Person):
        """学生类"""
    
        def eat(self):
            print("吃食堂")
    
        def sleep(self):
            print("睡宿舍")
    
    stu = Student()
    stu.sleep()
    stu.eat()
    stu.breath()
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值