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

news2024/12/24 2:06:24

文章目录

      • 一、面向对象与面向过程
            • 1、什么是面向过程?
            • 2、什么是面向对象?
      • 二、类与对象
        • 1. 初识对象
        • 2. 类的成员方法
            • 2.1 类的定义和使用
            • 2.2 成员方法
        • 3. 类和对象
        • 4. 魔法方法
            • 1. _ _ inint _ _ 构造方法
            • 2. _ _ str _ _ 字符串方法
            • 3. _ _ lt _ _ 小于符号比较方法
            • 4. _ _ le _ _ 小于等于比较符号方法
            • 5. _ _ eq _ _ 相等比较方法
      • 三、面向对象的三大特征:封装、继承、多态
        • 1. 封装
        • 2. 继承
        • 3. 多态
      • 四、类型注解
        • 1. 变量的类型注解
        • 2. 基础容器类型注解
        • 3. 类对象类型注解
        • 4. 函数形参和返回值的类型注解
        • 5. Union类型联合类型注解

一、面向对象与面向过程

面向对象编程(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()

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

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. 初识对象

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

以下是一个简单的示例:

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, 我叫李四.

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

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('请多多关照')

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

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

其中:

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

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

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

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

例如:

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

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

3. 类和对象

基于类创建对象的语法:

对象名 = 类名称()

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

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

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

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"

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

注意
在构造方法内定义成员变量,需要使用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>

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

内存地址没有多大作用,我们可以通过 _ _ 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
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)

像这样直接对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

比较大于符号的魔术方法是:_ _ 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)

在这里插入图片描述

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
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

不实现 _ _ 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

实现了 _ _ 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')

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

phone = Phone()
phone.__keep_5g()

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

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()
2. 继承

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

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

继承分为:单继承多继承

单继承语法

class 类名(父类):
	类内容体
# 单继承演示
# 定义父类
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

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

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

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

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

# 多继承演示
# 定义父类
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()  # 输出:红外遥控开启

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

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通话

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

方式一:

  • 调用父类成员
    使用成员变量:父类名.成员变量
    使用成员方法:父类名.成员方法(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()

在这里插入图片描述

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)  # 输出:格力空调制冷

四、类型注解

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

1. 变量的类型注解

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

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

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

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": "张三"}

注意

  • 元组类型设置类型详细注解,需要将每一个元素都标记出来
  • 字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
3. 类对象类型注解
# 类对象类型注解
class Student:
    pass

stu: Student = Student()
4. 函数形参和返回值的类型注解

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

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

返回值注解
语法

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

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

语法:# type: 类型

# 在注释中进行类型注解
var_1: random.randint(1, 10)  # type: int
var_2: json.loads('{"name": "张三"}')  # type: dict
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1460649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于python社交网络大数据分析系统的设计与实现

项目&#xff1a;基于python社交网络大数据分析系统的设计与实现 摘 要 社交网络大数据分析系统是一种能自动从网络上收集信息的工具&#xff0c;可根据用户的需求定向采集特定数据信息的工具&#xff0c;本项目通过研究爬取微博网来实现社交网络大数据分析系统功能。对于采集…

十二、通过色彩空间转换进行更换图片背景

项目功能实现&#xff1a;对一张白色背景的图片进行更换成蓝色背景&#xff0c;类似抠图更换背景操作 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 inrange.h #pragma once#include<opencv2/opencv.hpp>using namespace cv;class INRANGE{ public:v…

leetcode hot100组合综合四

本题中&#xff0c;是要求nums中求的总和为target的排列数&#xff0c;因为题中说了&#xff0c;元素顺序不同&#xff0c;则可以视为不同的结果之一。 所以&#xff0c;根据对背包问题的总结&#xff0c;本题中元素可以重复使用&#xff0c;是完全背包并且需要求排列数&#…

我是怎么用静态IP代理为Google账号保驾护航的

我为何要使用到静态IP代理服务 我是一名IT从业者&#xff0c;在很多年前就加入了一家跨国软件公司&#xff0c;日常需要在全世界各地跟甲方沟通&#xff0c;负责的工作中重要的一块就是Google广告&#xff0c;为此公司还特意给配置了一台笔记本电脑。 目录 我为何要使用到静态…

教学设计与课堂教学的关系是什么

当你走进教室&#xff0c;是否曾思考过这背后的精心策划&#xff1f;每一堂课的呈现&#xff0c;都源于细致的教学设计。那么&#xff0c;教学设计与课堂教学之间&#xff0c;又隐藏着怎样的秘密呢&#xff1f; 教学设计&#xff0c;就像是一部剧本&#xff0c;为演员&#xf…

Puppeteer 使用实战:如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(一)

文章目录 效果展示说明利用工具整体思路Puppeteer 使用笔记保持登录状态打开新的页面点击 dialog跳转页面设置页面可见窗口大小寻找元素等待元素出现 整体代码 效果展示 说明 看了看网上很少做这个功能&#xff0c;但是我有这个需求&#xff0c;就抽出时间写了个简单的工具目前…

preCICE流固耦合仿真资料整理

preCICE The coupling library for partitioned multi-physics simulations 资料 Tutorials preCICE—多物理场耦合工具介绍 My First Fluid-Solid Interaction Case CalculiX 流固耦合&#xff08;FESIM有限元分析&#xff09; Coupling with preCICE by Gerasimos Chourdak…

k8s-配置与存储-配置管理

文章目录 一、配置存储1.1 ConfigMap1.1.1.基于文件夹的创建方式1.1.2指定文件的创建方式1.1.3 配置文件创建configmap 1.2 Secret1.2.1Secret的应用与Docker仓库 Secret设置1. Kubernetes 中的 Secrets&#xff1a;创建 Secret 示例&#xff1a;将 Secret 挂载到 Pod 中的示例…

URL、DNS过滤,AV---防火墙综合实验

拓扑图 该实验之前的配置请看我的上一篇博客&#xff0c;这里仅配置URL、DNS过滤&#xff0c;AV 需求 8&#xff0c;分公司内部的客户端可以通过域名访问到内部的服务器 这次的拓扑图在外网多增加了一个DNS服务器和HTTP服务器 DNS服务器IP&#xff1a;40.0.0.30 HTTP服务器…

Pandas快问快答16-30题

16. 如何对一个Pandas数据框进行聚合操作? 聚合操作是数据处理中的一种重要方式&#xff0c;主要用于对一组数据进行汇总和计算&#xff0c;以得到单一的结果。在聚合操作中&#xff0c;可以执行诸如求和、平均值、最大值、最小值、计数等统计操作。这些操作通常用于从大量数…

WebGIS开发常用的JS库:VUE/React/Angular对比

Angular: 作用&#xff1a; Angular是一个完整的基于TypeScript的Web应用开发框架&#xff0c;主要用于构建单页Web应用&#xff08;SPA&#xff09;。它适用于大型和复杂的项目&#xff0c;具有强大的组件集合和丰富的文档。 架构&#xff1a; Angular采用组件化的方式&am…

19个Web前端交互式3D JavaScript框架和库

JavaScript &#xff08;JS&#xff09; 是一种轻量级的解释&#xff08;或即时编译&#xff09;编程语言&#xff0c;是世界上最流行的编程语言。JavaScript 是一种基于原型的多范式、单线程的动态语言&#xff0c;支持面向对象、命令式和声明式&#xff08;例如函数式编程&am…

ts快速入门

文章目录 一、运行环境1、线上Playground2、VSCode 编辑器3、Code Runner 插件4、ts-node 二、声明1、变量声明2、常量声明3、类型推断 三、常用数据类型1、number2、string3、boolean4、数组5、对象 四、函数1、函数声明语法2、参数详解&#xff08;1&#xff09;特殊语法&…

物体检测-系列教程8:YOLOV5 项目配置

1、项目配置 yolo的v1、v2、v3、v4这4个都有一篇对应的论文&#xff0c;而v5在算法上没有太大的改变&#xff0c;主要是对v4做了一个更好的工程化实现 1.1 环境配置 深度学习环境安装请参考&#xff1a;PyTorch 深度学习 开发环境搭建 全教程 要求torch版本>1.6&#xf…

基于Mapbox展示GDAL处理的3D行政区划展示实践

目录 前言 一、Gdal数据处理 1、数据展示 2、Java数据转换 二、Mapbox可视化 1、定义Mapbox地图 2、地图初始化 3、创建地图 三、界面优化 1、区域颜色设置 2、高度自适应和边界区分 3、中文标注 总结 前言 最近有遇到一个需求&#xff0c;用户想在地图上把行政区划…

Qt _day1

1.思维导图 2.设计一个简单登录界面 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {this->setWindowTitle("原神启动"); // this->setStyleSheet("background-color:rgb(255,184,64)");this->setStyl…

力扣爆刷第76天--动态规划完全背包和多重背包

力扣爆刷第76天–动态规划完全背包和多重背包 文章目录 力扣爆刷第76天--动态规划完全背包和多重背包一、139.单词拆分二、56. 携带矿石资源&#xff08;第八期模拟笔试&#xff09; 一、139.单词拆分 题目链接&#xff1a;https://leetcode.cn/problems/word-break/descripti…

华为OD机试真题C卷-篇5

100分值题 小朋友来自多少小区堆内存申请跳格子3测试用例执行计划 小朋友来自多少小区 nums [int(x) for x in input().split(" ")] #index为报告的结果&#xff0c;zones[index]为报告相同结果的总人数 zones [0 for x in range(1000)] count 0i0 while(True):if…

算法项目(2)—— LSTM、RNN、GRU(SE注意力)、卡尔曼轨迹预测

本文包含什么? 项目运行的方式(包教会)项目代码LSTM、RNN、GRU(SE注意力)、卡尔曼四种算法进行轨迹预测.各种效果图运行有问题? csdn上后台随时售后.项目说明 本文实现了三种深度学习算法加传统算法卡尔曼滤波进行轨迹预测, 预测效果图 首先看下不同模型的指标: 模型RM…

解锁服务器外联:TinyProxy一键搭建指南

引言 在服务器需要访问外网的情况下&#xff0c;由于网络安全等原因&#xff0c;许多生产服务器限制了对外网的访问。本文介绍如何通过在一台能够访问外网的服务器上部署TinyProxy来实现代理&#xff0c;使得其他服务器可以通过该代理访问外网。 安装 TinyProxy是一个轻量级…