• 面向对象详解,面向对象的三大特征:封装、继承、多态


    一、面向对象与面向过程

    面向对象编程(Object-Oriented Programming,简称OOP)和面向过程编程(Procedural Programming,简称PP)是两种不同的编程范式

    面向对象编程强调把问题分解成对象,通过封装、继承和多态等机制,来处理对象之间的关系。每个对象都可以独立地处理自己的数据和行为,而不需要依赖其他对象。面向对象编程更加注重代码的重用性、可维护性和可扩展性,适用于大型、复杂的软件系统开发。

    面向过程编程则是一种以过程为中心的编程方式,它将问题分解成一系列的步骤,然后按照顺序执行这些步骤,以达到求解问题的目的。在面向过程编程中,数据和操作是分离的,函数是处理数据的主要手段。面向过程编程更加注重效率和速度,适用于小型、简单的程序或者性能要求较高的场景。

    1、什么是面向过程?

    面向过程:问题分解成一系列的步骤,然后按照顺序执行这些步骤
    举个简单的例子
    相信大家都被问过这样一个问题: 把大象装入冰箱需要几步?
    在这里插入图片描述
    按照面向过程的思想:需要三步
    第一步:打开冰箱
    第二步:把大象塞进去
    第三步:关上冰箱
    在这里插入图片描述
    从这里就可以看出:面向过程就是把一件事按步骤一步一步来实现

    代码实现:

    # 第一步:打开冰箱门
    def open_door():
        print("打开冰箱门")
    
    # 第二步:把大象放进去
    def put_elephant():
        print("把大象放进去")
    
    # 第三步:关闭冰箱门
    def close_door():
        print("关闭冰箱门")
    
    # 完成三个步骤
    def put_elephant_in_fridge():
        open_door()
        put_elephant()
        close_door()
    
    # 测试程序
    put_elephant_in_fridge()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    这就是面向过程代码的具体实现啦

    2、什么是面向对象?

    对象:就是对问题中的事物的抽象
    对象可以说是对现实事物的一种抽象映射
    面向对象:就是把现实中的事物都抽象为“对象”。每个对象是唯一的,且都可以拥有它的属性与行为。我们就可以通过调用这些对象的方法、属性去解决问题。

    按照面向对象的思想
    在这里插入图片描述
    在这个例子中:
    我们可以把大象看作一个对象,冰箱看作一个对象。
    冰箱的一些功能:开门装物体关门

    class Elephant:  # 大象类
        def Eat(self):  # 吃
            print('吃')
    
    class Fridge:  # 冰箱类
        def open_door(self):  # 打开冰箱门
            print('打开冰箱门')
        
        def Put_In(self):  # 放入东西
            print('放入东西')
        
        def close_door(self):  # 关闭冰箱门
            print('关闭冰箱门')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在面向对象中,每个对象是独立的,有属于它自己的功能,只需要专心实现自己的功能就好。所以在建立对象模型阶段,仅仅关注对象有什么的功能,但不考虑如何实现这些功能。

    面向对象对象的特点:有很好的延展性,比如我给大象赋予了一个吃的功能,它通过调用就可以在冰箱里去吃东西。面向对象就是把现实问题抽象为对象,通过调用每个对象的属性或功能去解决问题。

    二、类与对象

    1. 初识对象

    什么是对象?
    对象是面向对象编程中的一个概念,它是类的一个实例化(即具体化)的结果。对象是具体的实际存在的,可以在程序中被创建操作销毁
    面向对象编程中,对象是由属性方法组成的。属性表示对象的状态和特征,方法表示对象可以执行的操作和行为
    每个对象都属于某个类,类是对象的抽象,它定义了对象所具有的属性方法结构和行为对象通过实例化类来创建,并且可以根据类的定义进行属性和方法的访问和调用。

    以下是一个简单的示例:

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        
        def say_hello(self):
            print(f"Hello, 我叫 {self.name}.")
    
    # 创建两个Person对象
    person1 = Person("张三", 25)
    person2 = Person("李四", 30)
    
    # 调用对象的方法
    person1.say_hello()  # 输出: Hello, 我叫张三.
    person2.say_hello()  # 输出: Hello, 我叫李四.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    通过创建对象,我们可以根据类的定义来操作和管理数据,并执行对象所具有的行为。

    2. 类的成员方法
    2.1 类的定义和使用

    在python中,用关键字class来定义类
    在这里插入图片描述

    # 定义一个带有成员方法的类
    class Student:
        # 成员变量
        name = None  # 学生的姓名
        # 定义方法
        def say_hi1(self):
            print(f'大家好,我叫{self.name}')  # 成员方法中访问成员变量必须要用self关键字!
    
        def say_hi2(self, msg):
            print(f'大家好,我是{self.name},{msg}')  # msg为外部传入的不需要用self!
    
    stu1 = Student()
    stu1.name = '张三'
    stu1.say_hi1()
    stu2 = Student()
    stu2.name = '李四'
    stu2.say_hi2('请多多关照')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行结果:
    在这里插入图片描述
    可以看出,在类中:

    • 不仅可以定义属性用来记录数据
    • 也可以定义函数,用来记录行为

    其中:

    • 类中定义的属性(变量),我们称之为:成员变量
    • 类中定义的行为(函数),我们称之为:成员方法
    2.2 成员方法

    语法
    在类中定义成员方法和定义函数基本一致,只存在细微区别:

    在这里插入图片描述
    注意:self关键字是成员方法定义的时候,必须填写的。

    • 它用来表示类对象自身的意思
    • 当我们使用类对象调用方法的是,self会自动被python传入
    • self出现在形参列表中,但是不占用参数位置,无需理会
    • 在方法内部,想要访问类的成员变量,必须使用self

    例如:

    class Student:
        # 成员变量
        name = None  # 学生的姓名
        # 定义方法
        def say_hi(self):
            print(f'大家好,我叫{self.name}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    class Student:
        # 成员变量
        name = None  # 学生的姓名
        def say_hi(self, msg):
            print(f'大家好,{msg}')  # msg为外部传入的不需要用self!
            
    stu = Student()
    stu.say_hi('请多多关照')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    可以看到,在传入参数的时候,没有传入self,但也没有报错。

    3. 类和对象

    基于类创建对象的语法:

    对象名 = 类名称()
    
    • 1

    为什么非要创建对象才能使用呢?

    类只是一种程序内的“设计图纸”或者摸具,需要基于图纸或摸具生产实体(对象),才能正常工作这种套路,称之为:面向对象编程

    举一个简单的例子:
    就相当于是闹钟的设计图纸,而对象就相当于按照闹钟的设计图纸所生产出来的闹钟
    在这里插入图片描述
    在这里插入图片描述
    从上面可以看出,设计出来的类包含编号和价格,具有响铃的功能。而基于类所创建的对象也有对应的编号和价格
    所以面向对象编程就是设计类,基于类创建对象,由对象做具体的工作

    4. 魔法方法

    内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为:魔术方法
    常见的魔法方法:

    魔法方法描述
    _ _ init _ _(self, …)初始化方法,用于初始化对象的属性,在对象创建时调用。
    _ _ str _ _(self)将对象转换为字符串的方法,可以通过str(obj)或print(obj)来触发,返回对象的可读性好的字符串表示。
    _ _ repr _ _(self)将对象转换为供解释器读取的形式的字符串,通常用于调试和开发,可以通过repr(obj)来触发。
    _ _ len _ _(self)返回对象的长度,可以通过len(obj)来调用。
    _ _ getitem _ _(self, key)获取对象的索引值,用于支持索引操作,如obj[key]。
    _ _ setitem _ _(self, key, value)设置对象的索引值,用于支持赋值操作,如obj[key] = value。
    _ _ delitem _ _(self, key)删除对象的索引值,用于支持删除操作,如del obj[key]。
    _ _ iter _ _(self)返回一个迭代器,用于支持对象的迭代功能,如在for循环中使用。
    _ _ next _ _(self)用于迭代器,返回迭代对象的下一个元素。
    _ _ eq _ _(self, other)定义对象相等的比较方式,通常用于==操作符的比较。
    _ _ lt _ _(self, other)定义对象小于的比较方式,通常用于<操作符的比较。
    _ _ add _ _(self, other)定义对象相加的方式,通常用于+操作符的运算。
    _ _ sub _ _(self, other)定义对象相减的方式,通常用于-操作符的运算。
    _ _ mul _ _(self, other)定义对象相乘的方式,通常用于*操作符的运算。
    _ _ div _ _(self, other)定义对象相除的方式,通常用于/操作符的运算。

    上述表格因为语法限制,把下面的下划线之间都空了一格,实际上两条下划线之间并没有空格!

    常见的魔法方法
    在这里插入图片描述

    1. _ _ inint _ _ 构造方法
    class Student:
        name = None  # 姓名
        age = None  # 年龄
        tel = None  # 手机号
    
    stu1 = Student()
    stu1.name = '张三'
    stu1.age = 18
    stu1.tel = "1686400001"
    stu2 = Student()
    stu2.name = '李四'
    stu2.age = 19
    stu2.tel = "163200002"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    上面代码中,为对象的属性赋值需要依次进行,略显繁琐。可不可以像函数传参那样直接一次性对属性进行赋值呢?
    答案是肯定的,需要使用构造方法:_ _ init _ _()

    Python类可以使用:_ _ init _ _() 方法,称之为构造方法。
    可以实现:

    • 在创建类对象(构造类)的时候,会自动执行。
    • 在创建类对象(构造类)的时候,将传入参数自动传递给__init__方法使用。
    class Student:
        # 成员对象
        """
        __init__构造方法里对成员变量进行了声明并赋值
        所以成员对象这里可省略
        """
        name = None
        age = None
        tel = None
    
        def __init__(self, name, age, tel):
            self.name = name
            self.age = age
            self.tel = tel
            print('Student类创建了一个类对象')  # 输出:Student类创建了一个类对象
    
    stu1 = Student('张三', '18', '13066660')
    print(stu1.name)  # 输出:张三
    print(stu1.age)  # 输出:18
    print(stu1.tel)  # 输出:13066660
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    注意
    在构造方法内定义成员变量,需要使用self关键字
    在这里插入图片描述
    这是因为:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。

    2. _ _ str _ _ 字符串方法
    • 方法名:_ _ str _ _
    • 返回值:字符串
    • 内容:自行定义
    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    stu1 = Student('张三', 18)
    print(stu1)  # 输出:<__main__.Student object at 0x000001EDFFB09FD0>
    print(str(stu1))  # 输出:<__main__.Student object at 0x000001EDFFB09FD0>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当类对象需要被转换为字符串之时,会输出如上结果(内存地址)

    内存地址没有多大作用,我们可以通过 _ _ str _ _ 方法,控制类转换为字符串的行为。

    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
        def __str__(self):
            return f'name:{self.name}, age:{self.age}'
            
    stu1 = Student('张三', 18)
    print(stu1)  # 输出:name:张三, age:18
    print(str(stu1))  # 输出:name:张三, age:18
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    3. _ _ lt _ _ 小于符号比较方法
    • 方法名:_ _ lt _ _
    • 传入参数:other,另一个类对象
    • 返回值:True 或 False
    • 内容:自行定义
    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    stu1 = Student('张三', 18)
    stu2 = Student('李四', 19)
    print(stu1 < stu2)
    print(stu1 > stu2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    像这样直接对2个对象进行比较是不可以的
    在这里插入图片描述
    在类中实现 _ _ lt _ _ 方法,可同时完成:小于符号和大于符号2种比较。

    • 方法名:_ _ lt _ _
    • 传入参数:other,另一个类对象
    • 返回值:True 或 False
    • 内容:自行定义
    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        # __lt__魔法方法: 两个类对象进行大于或小于的比较
        def __lt__(self, other):
            return self.age < other.age
    
    stu1 = Student('张三', 18)
    stu2 = Student('李四', 19)
    print(stu1 < stu2)  # 输出:True
    print(stu1 > stu2)  # 输出:False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    比较大于符号的魔术方法是:_ _ gt _ _, 方法和 _ _ lt _ _ 一样,所以实现了 _ _ lt _ __ _gt _ _ 就没必要实现了。

    4. _ _ le _ _ 小于等于比较符号方法

    这个和 _ _ lt _ _ 一样,唯一不同的是 _ _ lt _ _ 是比较大于或小于,而 _ _ le _ _ 则是比较大于等于和小于等于。

    • 方法名:_ _ le _ _
    • 传入参数:other,另一个类对象
    • 返回值:True 或 False
    • 内容:自行定义
    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
        # __lt__魔法方法: 两个类对象进行大于或小于的比较
        def __lt__(self, other):
            return self.age < other.age
            
    stu1 = Student('张三', 18)
    stu2 = Student('李四', 19)
    print(stu1 <= stu2)
    print(stu1 >= stu2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
        # __lt__魔法方法: 两个类对象进行大于或小于的比较
        def __lt__(self, other):
            return self.age < other.age
    
    	# __le__魔法方法: 两个类对象进行大于等于或小于等于的比较
        def __le__(self, other):
            return self.age <= other.age
    
    stu1 = Student('张三', 18)
    stu2 = Student('李四', 19)
    print(stu1 <= stu2)  # 输出:True
    print(stu1 >= stu2)  # 输出:False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    5. _ _ eq _ _ 相等比较方法
    • 方法名:eq
    • 传入参数:other,另一个类对象
    • 返回值:True 或 False
    • 内容:自行定义
    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    stu1 = Student('张三', 18)
    stu2 = Student('李四', 19)
    print(stu1 == stu2)  # 输出:False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    不实现 _ _ eq _ _ 方法,对象之间也可以进行比较,但是是比较内存地址,也即是:不同对象==比较一定是False结果

    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
        # __eq__魔法方法: 两个类对象进行相等的比较
        def __eq__(self, other):
            return self.age == other.age
    stu1 = Student('张三', 18)
    stu2 = Student('李四', 18)
    print(stu1 == stu2)  # 输出:True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    实现了 _ _ eq _ _ 方法,就可以按照自己的想法来决定2个对象是否相等了。

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

    1. 封装

    封装(Encapsulation):将数据和操作封装在对象中,使其成为一个独立的实体,外界只能通过对象提供的接口访问和操作内部数据
    在这里插入图片描述
    对用户隐藏的属性和行为
    现实世界中的事物,有属性和行为。但是不代表这些属性和行为都是开放给用户使用的。

    私有成员
    既然现实事物有不公开的属性和行为,那么作为现实事物在程序中映射的类,也应该支持。

    类中提供了私有成员的形式来支持。

    • 私有成员变量
    • 私有成员方法

    定义私有成员的方式非常简单,只需要:

    • 私有成员变量:变量名以__开头(2个下划线)
    • 私有成员方法:方法名以__开头(2个下划线)
    class Phone:
        IMEI = None  # 序列号
        producer = None  # 厂商
        # 私有成员变量
        __current_voltage = None  # 当前电压
    
        def call_by_5g(self):
            print('5g通话已开启')
    	
    	# 私有成员方法
        def __keep_5g(self):
            print('保持5g')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    私有方法无法直接被类对象使用

    phone = Phone()
    phone.__keep_5g()
    
    • 1
    • 2

    在这里插入图片描述
    使用私有成员

    class Phone:
        # 构造方法
        def __init__(self, __is_5g_enable):
            # 设置私有变量
            self.__is_5g_enable = __is_5g_enable
    
        # 设置私有方法
        def __check_5g(self):
            if self.__is_5g_enable == True:  # 类内部访问私有成员要用self
                print('5G开启')
            else:
                print('5G关闭,使用4G网络')
    
        def call_by_5g(self):
            self.__check_5g()
            print('正在通话中...')
    
    phone = Phone(False)
    phone.call_by_5g()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    2. 继承

    继承(Inheritance):继承允许一个类(子类)继承另一个类(父类)的属性和方法,子类可以重用父类的代码,并且可以在不修改原有代码的情况下进行扩展和修改。
    简单来说就是一个类,继承另外一个类的成员变量和成员方法

    举个简单的例子:
    手机的更新换代并不是完完全全重新开始,而是在原先的基础上新添一些属性和功能。
    在这里插入图片描述
    类比到程序中,我们也可以在已经设计好的类上进行更新和修改,这就会用到继承。

    继承分为:单继承多继承

    单继承语法

    class 类名(父类):
    	类内容体
    
    • 1
    • 2
    # 单继承演示
    # 定义父类
    class Phone:
        IMEI = None  # 序列号
        producer = 'APPLE'  # 厂商
    
        def call_by_4g(self):
            print('4g通话')
    
    # 定义子类
    class Phone2022(Phone):
        face_id = '10001'
    
        def call_by_5g(self):
            print('5g通话')
    
    phone = Phone2022()
    phone.call_by_4g()  # 输出:4g通话
    print(phone.producer)  # 输出:APPLE
    phone.call_by_5g()  # 输出:5g通话
    print(phone.face_id)  # 输出:10001
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    通过继承可以将从父类那里继承(复制)来成员变量和成员方法(不含私有)给子类使用。

    多继承语法
    Python的类之间也支持多继承,即一个类,可以继承多个父类

    class 类名(父类1, 父类2, 父类3, ... , 父类N):
    	类内容体
    
    • 1
    • 2

    举例:
    在这里插入图片描述

    # 多继承演示
    # 定义父类
    class Phone:
        IMEI = None  # 序列号
        producer = 'HM'  # 厂商
    
        def call_by_4g(self):
            print('4g通话')
    
    class NFCReader:
        nfc_type = '第五代'
        producer = 'HM'
    
        def read_card(self):
            print('读取NFC卡')
    
        def write_card(self):
            print('写入NFC卡')
    
    class RemoteControl:
        rc_type = '红外遥控'
    
        def control(self):
            print('红外遥控开启')
    
    # 定义子类
    class MyPhone(Phone, NFCReader, RemoteControl):
        pass
    
    phone = MyPhone()
    print(phone.producer)  # 输出:HM
    print(phone.nfc_type)  # 输出:第五代
    phone.read_card()  # 输出:读取NFC卡
    phone.call_by_4g()  # 输出:4g通话
    phone.control()  # 输出:红外遥控开启
    
    • 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

    多继承注意事项:多个父类中,如果有同名的成员,那么**默认以继承顺序(从左到右)**为优先级。即:先继承的保留,后继承的被覆盖。

    pass语句
    pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思

    复写
    子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。
    即:在子类中重新定义同名的属性或方法即可。

    # 定义父类
    class Phone:
        IMEI = None  # 序列号
        producer = 'APPLE'  # 厂商
    
        def call_by_4g(self):
            print('4g通话')
    
    # 定义子类
    class MyPhone(Phone):
        producer = 'HUAWEI'  # 复写父类属性
    
        def call_by_4g(self):  # 复写父类方法
            print('可用5g通话')
    
    phone = MyPhone()
    print(phone.producer)  # 输出:HUAWEI
    phone.call_by_4g()  # 输出:可用5g通话
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    调用父类同名成员
    一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
    如果需要使用被复写的父类的成员,需要特殊的调用方式:

    方式一:

    • 调用父类成员
      使用成员变量:父类名.成员变量
      使用成员方法:父类名.成员方法(self)

    方式二:

    • 使用super()调用父类成员
      使用成员变量:super().成员变量
      使用成员方法:super().成员方法()

    注意:只能在子类内调用父类的同名成员。子类的类对象直接调用会调用子类复写的成员

    # 定义父类
    class Phone:
        IMEI = None  # 序列号
        producer = 'APPLE'  # 厂商
    
        def call_by_4g(self):
            print('4g通话')
    
    # 定义子类
    class MyPhone(Phone):
        producer = 'HUAWEI'  # 复写父类属性
    
        def call_by_4g(self):  # 复写父类方法
            print('可用5g通话')
            # 调用父类属性和方法
            # 方法一
            # print(f'调用父类属性[1]:{Phone.producer}')  # 调用父类属性
            # Phone.call_by_4g(self)  # 调用父类方法
            # 方法二
            print(f'调用父类属性[2]:{super().producer}')  # 调用父类属性
            super().call_by_4g()  # 调用父类方法
    
    phone = MyPhone()
    print(phone.producer)
    phone.call_by_4g()
    
    • 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

    在这里插入图片描述

    3. 多态

    多态(Polymorphism):多态使得对象可以根据上下文表现出不同的行为,同一个方法可以在不同对象上有不同的实现。这样可以提高代码的灵活性和可复用性。
    也就是说:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。

    如何理解?
    在这里插入图片描述
    同样的行为(函数),传入不同的对象,得到不同的状态
    在这里插入图片描述
    多态常作用在继承关系上。
    比如

    • 函数(方法)形参声明接收父类对象
    • 实际传入父类的子类对象进行工作

    即:

    • 以父类做定义声明
    • 以子类做实际工作
    • 用以获得同一行为, 不同状态

    抽象类(接口)
    抽象类:含有抽象方法的类称之为抽象类
    抽象方法:方法体是空实现的(pass) 称之为抽象方法

    举例
    在这里插入图片描述

    # 抽象类
    # 定义父类
    class AC:
        def cool_wind(self):
            """制冷"""
            pass
    
        def hot_wind(self):
            """制热"""
            pass
    
        def swing_l_r(self):
            """左右摆风"""
            pass
    
    class Midea_AC(AC):
        def cool_wind(self):
            print('美的空调制冷')
    
        def hot_wind(self):
            print('美的空调制热')
    
        def swing_l_r(self):
            print('美的空调左右摆风')
    
    class GREE_AC(AC):
        def cool_wind(self):
            print('格力空调制冷')
    
        def hot_wind(self):
            print('格力空调制热')
    
        def swing_l_r(self):
            print('格力空调左右摆风')
    
    def cool_wind(ac: AC):
        ac.cool_wind()
    
    # 创建对象
    midea = Midea_AC()
    gree = GREE_AC()
    cool_wind(midea)  # 输出:美的空调制冷
    cool_wind(gree)  # 输出:格力空调制冷
    
    • 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

    四、类型注解

    在PyCharm中编写代码,我们经常能够见到如下提示:
    在这里插入图片描述
    为什么PyCharm工具能够做到这一点?
    因为:PyCharm确定这个对象,是list类型
    同样,我们换一份代码:定义一个函数func,接收一个参数data,你会发现,PyCharm不会在做出任何提示了
    在这里插入图片描述
    为什么PyCharm工具无法提示了?
    这是因为PyCharm不确定这个对象是什么类型
    PyCharm无法通过代码确定应传入什么类型,我们需要使用类型注解

    1. 变量的类型注解

    基础语法: 变量: 类型
    为变量设置注解,显示的变量定义,一般无需注解

    # 变量的类型注
    var1: int = 10
    var2: str = '张三'
    var3: bool = True
    
    • 1
    • 2
    • 3
    • 4

    像上面这样:就算不写注解,也明确的知晓变量的类型

    2. 基础容器类型注解
    # 基础容器类型注解
    my_list: list = [1, 2, 3]
    my_tuple: tuple = (1, 2, 3)
    my_dict: dict = {"name": "张三"}
    
    # 容器类型详细注解
    my_list1: list[int] = [1, 2, 3]
    my_tuple1: tuple[int, str, bool] = (1, "张三", True)
    my_dict1: dict[str, str] = {"name": "张三"}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意

    • 元组类型设置类型详细注解,需要将每一个元素都标记出来
    • 字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
    3. 类对象类型注解
    # 类对象类型注解
    class Student:
        pass
    
    stu: Student = Student()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4. 函数形参和返回值的类型注解

    函数和方法的形参类型注解语法:

    def 函数名(形参1: 类型, 形参2: 类型, ..., 形参n: 类型):
    	pass
    
    • 1
    • 2
    # 函数形参的类型注解
    def add(x: int, y: int):
        return x + y
    
    • 1
    • 2
    • 3

    返回值注解
    语法

    def 函数名(形参1: 类型, 形参2: 类型, ..., 形参n: 类型) -> 返回值类型:
    	pass
    
    • 1
    • 2
    # 函数形参和返回值的类型注解
    def fnuc(data: list) -> list:
        return data
    
    • 1
    • 2
    • 3

    除了使用 变量: 类型, 这种语法做注解外,也可以在注释中进行类型注解。

    语法:# type: 类型

    # 在注释中进行类型注解
    var_1: random.randint(1, 10)  # type: int
    var_2: json.loads('{"name": "张三"}')  # type: dict
    
    • 1
    • 2
    • 3
    5. Union类型联合类型注解

    Union 类型用于指定一个变量可以是多种类型中的一种。
    Union联合类型注解,在变量注解、函数(方法)形参和返回值注解中,均可使用。

    Union的使用方式
    导包:from typing import Union
    语法:Union[类型, …, 类型]

    # 使用Union类型,必须先导包
    from typing import Union
    
    my_list: list[Union[int, str, dict]] = [1, 2, 'name', {"age": 18}]
    my_dict: dict[str, Union[int, str, list]] = {"name": "张三", "age": 18, "grade": [98, 97]}
    my_list1: list[Union[int, str, dict[Union[str, int]]]] = [1, 2, 'name', {"age": 18}]
    
    # 函数的Union类型
    def func(data: Union[int, str]) -> Union[int, str]:
        return data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    贪心算法一:最优装载问题
    基于MATLAB的蒲公英算法求解单目标优化问题
    Linux常用命令-2
    Qt/C++原创推流工具/支持多种流媒体服务/ZLMediaKit/srs/mediamtx等
    8.深度学习DNN
    提取歌曲伴奏?用对软件一键帮你搞定~
    在 PostgreSQL 中,解决图片二进制数据,由于bytea_output参数问题导致显示不正常的问题。
    六大维度全面焕新升级!麒麟信安服务器操作系统V3.6.1引领未来计算
    混凝土粉末
    全自主巡航无人机项目思路:STM32/PX4 + ROS + AI 实现从传感融合到智能规划的端到端解决方案
  • 原文地址:https://blog.csdn.net/dh45498/article/details/136150045