• 【python】(六)python的封装、继承和多态



    1. python面向对象编程

    1.1 面向对象是什么

    • Python 是一门面向对象的语言
    • 面向对象编程(OOP):Object Oriented Programming

    所谓的面向对象,就是在编程的时候尽可能的去模拟真实的现实世界,按照现实世界中的逻辑去处理问题,分析问题中参与其中的有哪些实体,这些实体应该有什么属性和方法,我们如何通过调用这些实体的属性和方法去解决问题。

    1.2 两种编程思想

    1. 面向过程

      • 一种以过程为中心的编程思想
      • 首先分析解决问题所需要的步骤
      • 然后用函数将这些步骤一步一步的实现
      • 最后按顺序依次调用运行
    2. 面向对象

      • 是一种更符合我们人类思维习惯的编程思想
      • 面向对象开发就是不断的创建对象,使用对象,操作对象做事情
      • 可以将复杂的事情简单化

    1.3 类与对象

    • 类(class): 用来描述具有相同的属性和方法的对象的集合。它定义了集合中每个对象所共有的属性和方法。
    • 对象(object):也称为类的实例,是一个具体存在的实体。

    2. python类与对象

    2.1 类的定义

    • class 关键字
    # 语法
    class 类名(父类名):
        """类的帮助信息"""
        属性
        方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    # class_def.py
    
    # 类的声明
    class Human(object): #object可以省略。在python中如果没有声明继承的类的话,那默认继承的是超类object。
        """人类"""
        # 定义属性(类属性)
        message = "这是类属性"
    
    # 通过类访问类属性
    print(Human.message)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.2 类的方法

    2.2.1 实例方法

    2.2.1.1 构造方法
    • 作用:实例化对象。构造方法用于构造并直接返回该类的对象,每当创建一个类的新的实例时,python会自动执行构造方法,这是创建对象的基本途径。如果开发者没有在类中定义构造方法,python会自动给该类默认添加一个构造方法。
    • 语法:def __init__(self, 参数列表)
      • self:self参数是一个指向实例的引用,用于访问类的属性和方法,在方法调用时会自动绑定到调用这个方法的本身。
      • self参数必须有,且必须处于首位。
    • 访问:类名(参数列表)
    # constructor_method.py
    
    class Human:
    
        # 定义属性(类属性)
        message = "这是类属性"
    
        # 构造方法
        def __init__(self, name, age):  
            # 实例变量(实例属性)
            self.name = name
            self.age = age
            print("这是构造方法")
    
    # 实例化对象
    person = Human("哈利波特", 12)
    
    # 通过实例访问类属性
    print(person.message)
    
    # 通过实例访问实例属性
    print(person.name)
    print(person.age)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    2.2.1.2 实例方法
    • 作用:实例方法是在类中定义的函数,该函数是一种在类的实例上操作的函数。实例方法提供每个类的实例共享的方法
    • 语法:def 方法名(self, 参数列表)
      • self:类的实例自身,也可以是self之外的其他单词,但建议使用约定俗成的self。第一个参数必须是self,不可省略。
      • 参数列表:自定义参数,每个参数间使用逗号分隔
    • 访问:实例.方法名(参数列表)
    • 实例方法与函数的区别:函数是实现某个独立功能;实例方法是实现类的某个行为,属于类的部分。实例方法用于定义该类的对象行为和行为实现。在类中的方法都属于实例方法。
    # instance_method.py
    
    
    class Human:
    
        # 实例方法
        def study(self, course):
            print("正在学习{course}")
    
    # 实例化
    person = Human()
    
    # 通过实例访问实例方法
    person.study("python")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.2.2 类方法

    • 作用:类方法是指在类中使用 @classmethod 装饰器装饰的方法。用于设置或获取类的详细信息或者状态。
    • 语法:@classmethod
    • 访问:类名.类方法名(参数列表)
    • 注意:不能访问或者修改实例对象的数据 ,因为类方法绑定的是cls参数不是self参数。不使用cls不会报错,但是最好按照惯例来,cls指向对象其实就是类名本身。
    # class_method.py
    
    class Human:
    
        # 类属性
        population = []
    
        # 类方法
        @classmethod
        def born(cls): #使用类方法装饰器,定义类时会自动添加cls参数
            print("这是类方法")
            cls.population += 1
    
    
    # 通过类名访问类方法
    Human.born()
    print(Human.population)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.2.3 静态方法

    • 静态方法是类中使用@staticmethod装饰的方法。静态方法不需要访问数据,没有cls、self这种关键字。静态函数可以独立工作,不能设置类的状态或者实例的状态。
    • 作用:静态方法用于创建通用的工具函数。这样就可以把常用的工具函数放在一个类里,使用的时候不需要实例化就可以直接调用。
    • 语法:@staticmethod
    • 调用:类名.静态方法名()
    • 注意:调用类方法和静态方式时,我们是使用类名访问。虽然实例也可以调用类方法和静态方法,但是一般不会这样进行操作。这样可以省去实例化的步骤。
    # static_method.py
    
    class Human:
    
        # 静态方法
        @staticmethod
        def grow_up():#使用静态方法声明后,不会绑定cls或者self参数
            print("这是静态方法")
    
    # 通过类名访问静态方法
    Human.grow_up()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3. python封装

    3.1 封装的概念

    封装(Encapsulation):

    • 隐藏:属性和实现细节,不允许外部直接访问
    • 暴露:公开方法, 实现对内部信息的操作和访问

    3.2 封装的作用

    • 限制不合理的访问和操作,提高数据安全性
    • 可进行数据检查,从而有利于保证对象信息的完整性

    3.3 封装的实现

    3.3.1 隐藏

    python中没有既定的关键字或者机制来实现真正的封装,但是使用命名方式来实现

    • 保护属性:_属性名
    • 私有属性:__属性名
      • 定义私有属性之后,python将会自动添加_类名,变相的实现了属性的隐藏,即被视为: _类名__属性名
      • 当想要通过__属性名去访问属性的话,实际上访问不到的。
    #定义一个Account类
    class Account:
    
        # 普通属性
        bank = "BOC"
        # 内部属性
        _username = "Hogwarts"
        # 私有属性
        __password = "888"
    
    
    # 通过类名访问类属性
    print(Account.bank)       # 将会打印 BOC
    print(Account._username)  # 将会打印 Hogwarts
    print(Account.__password) # 将会引发 AttributeError,打印内容:AttributeError: type object 'Account' has no attribute '__password'
    print(Account.__dict__)   # 将会打印类中实际有用属性
    #打印内容:{'__module__': '__main__', 'bank': 'BOC', '_username': 'Hogwarts', '_Account__password': '888', '__dict__': , '__weakref__': , '__doc__': None}
    #注:__dict__:python内置特殊属性,字典格式,保存类中所拥有的可写的属性
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.3.2 暴露

    1. 提供数据访问功能(getter)
    • 计算属性(通过@property合成的属性成为计算属性)
    • 语法:使用@property装饰器
    • 作用:把类中的一个方法变成一个属性
    • 调用:实例.方法名

    注意: 计算属性并不真正的存储状态,其值是通过某种算法计算得到的,当程序对该属性赋值时,所赋值实际是存放在对应的实例变量中。

    class Account:
        # 普通属性
        bank = "BOC"
        # 内部属性
        _username = "Hogwarts"
        # 私有属性
        __password = "888"
    
        @property
        def password(self):
            return self.__password
    
    # 实例化对象
    obj = Account()
    
    # 访问实例的私有属性
    print(obj.password)  # 将会打印 888
    #注意:password虽然是方法,但是已经被装饰成计算属性,因此访问的时候不需要加()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    1. 提供数据操作功能(setter)
    • 语法:使用@计算属性名.setter装饰器
    • 作用:对计算属性进行赋值操作
    • 调用:实例.方法名
    class Account:
        # 普通属性
        bank = "BOC"
        # 内部属性
        _username = "Hogwarts"
        # 私有属性
        __password = "888"
    
        @property
        def password(self):
            return self.__password
    
        @password.setter
        def password(self, value):
            # 增加数据的校验
            if len(value) >= 8:
                self.__password = value
            else:
                print("密码长度最少要有8位!")
    
    # 实例化对象
    obj = Account()
    
    # 修改私有属性(满足校验条件)
    obj.password = "hogwarts666"  # 修改成功
    print(obj.password)  # 将会打印 hogwarts666
    
    # 修改私有属性(不满足校验条件)
    obj.password = "123"  # 修改不会生效
    print(obj.password)  # 将会打印 888
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    4. python继承

    4.1 继承的概念

    继承(Inheritance):

    • 复用父类的公开属性和方法
    • 拓展出新的属性和方法

    4.2 继承的实现

    • 语法:class 类名(父类列表)
    • 默认父类是 object
    • Python 支持多继承
    # inheritance_demo.py
    
    class Human:
        """人类"""
    
        # 类属性
        message = "这是Human的类属性"
    
        # 构造方法
        def __init__(self, name, age):
            # 实例属性
            self.name = name
            self.age = age
    
        # 实例方法
        def live(self):
            print("住在地球上")
    
    
    class Student(Human):
        """学生类"""
    
        def study(self):
            print("正在学习")
    
    
    # 实例化子类对象
    stu = Student("哈利波特", 12)
    # 访问类属性(继承)
    print(stu.message)
    # 访问实例属性(继承)
    print(stu.name, stu.age)
    # 访问实例方法(继承)
    stu.live()
    # 访问实例方法(扩展)
    stu.study()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    4.3 类型检查

    • isinstance(实例, 类名)
      • 检查对象是否是某个类及其派生类的实例
    • issubclass(类名1, 类名2)
      • 检查类名 1 是否是类名 2 的子类
    # relation_demo.py
    
    # 人类
    class Human:
        pass
    
    # 学生类
    class Student(Human):
        pass
    
    # 老师类
    class Teacher(Human):
        pass
    
    # 检查实例与类的关系
    stu = Student()
    print(isinstance(stu, Human))  # 将会打印 True
    
    # 检查类与类的关系
    print(issubclass(Student, Human))  # 将会打印 True
    print(issubclass(Student, Teacher))  # 将会打印 False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    5. python多态

    5.1 多态的概念

    多态(Polymorphism):同名方法呈现多种行为

    python弱类型语言,变量并没有声明类型,因此完全可以在不同的时间代表不同的变量,当同一个变量在调用同一个方法时,完全可能呈现出多种行为,具体呈现的哪些行为由该变量所引用的对象来决定。这就是多态。

    5.2 多态的表现

    5.2.1 运算符的多态表现

    • +
      • 加法:数字+数字
      • 拼接:字符串+字符串
      • 合并:列表+列表
    # 加法:数字+数字
    print(1 + 1)  # 打印 2
    
    # 拼接:字符串+字符串
    print("Hello" + "World")  # 打印 Hello World
    
    # 合并:列表+列表
    print([1, 2] + [3])  # 打印 [1, 2, 3]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.2.2 函数的多态表现

    • len()函数

      • 可以接收字符串
      • 可以接收列表
    # 参数是字符串
    print(len("Hogwarts"))
    
    # 参数是列表
    print(len([1, 3, 5]))
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.2.3 方法的多态表现

    同名变量调用同名方法呈现多种行为。

    # poly_method.py
    
    class China:
        def speak(self):
            print("汉语")
    
    class Usa:
        def speak(self):
            print("英语")
    
    # 实例化对象
    cn = China()
    us = Usa()
    
    for x in (cn, us):
        # 同一个变量在调用同名方法时,呈现不同的行为
        # 具体呈现哪种行为,由该变量所引用的对象决定
        x.speak()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    5.3 多态与继承

    • 方法重写(Override):子类的方法名称与父类的相同
    • 重写构造方法
      • super().__init__()
      • 父类名.__init__(self)
    # override_demo.py
    
    class Human:
        """人类"""
    
        message = "这是Human的类属性"
    
        # 构造方法
        def __init__(self, name, age):
            # 实例属性
            self.name = name
            self.age = age
    
        # 实例方法
        def live(self):
            print(f"住在地球上")
    
    
    class Student(Human):
        """学生类"""
    
        # 重写父类的构造方法
        def __init__(self, name, age, school):
            # 方式一:访问父类的构造方法
            super().__init__(name, age)
      
            #方式二:访问父类的构造方法
            # super(Student, self).__init__(name, age)
    
            #方式三:访问父类的构造方法
            # Human.__init__(self, name, age)
       
    	# 子类特有的实例属性(个性)
            self.school = school
    
        # 重写父类的实例方法
        def live(self):
            print(f"住在{self.school}")
    
    
    # 实例化子类对象
    stu = Student("哈利波特", 12, "Hogwarts")
    
    # 访问实例方法
    stu.live()  # 将会打印 住在Hogwarts
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    Webpack干货系列 | 在 Webpack 5 集成 ESLint 的方法
    Pyside6 QMessageBox
    JavaWeb 学习笔记 6:会话跟踪
    SpringMVC文件的上传下载&JRebel的使用
    PCL 点云超体素分割-SupervoxelClustering
    深入理解JNINativeInterface函数<三>
    【LeetCode】11. 盛最多水的容器
    redis高可用
    T31开发笔记:MP4录制
    Python复习知识点(二)
  • 原文地址:https://blog.csdn.net/gjj920318/article/details/126834584