[python] Python类型提示指北

news2024/9/23 13:15:57

Python3.5 版本引入了类型提示(Type Hints),它允许开发者在代码中显式地声明变量、函数、方法等的类型信息。这种类型声明不会影响 Python 解释器的运行,但可以让 IDE 和静态分析工具更好地理解代码,同时提高代码的可读性和可维护性。然而,由于 Python 支持动态类型,类型提示并不能完全确保代码的正确性。本文仅介绍 Python 类型提示的初步使用。如果需要更详细的使用说明,请参考以下文章:typing、Python 类型提示简介和Type Hints 入门教程。

类型提示的语法格式为:

  • 对于变量:{变量名}:{类型名} = {初始值}
  • 对于函数参数:{参数名}:{类型名} = {默认值}
  • 对于函数返回值:->{类型名}

文章目录

  • 1 类型提升
  • 2 类型声明
    • 2.1 基本类型
    • 2.2 嵌套类型
    • 2.3 自定义类型
    • 2.4 复合类型
      • 2.4.1 Union和Optional
      • 2.4.2 Generator和Iterator
      • 2.4.3 Callable
      • 2.4.4 Any和NoReturn
      • 2.4.5 其他
    • 2.5 类型提示的别名
  • 3 参考

1 类型提升

类型提示的引入主要有以下几个方面的用途:

1 提高代码可读性

类型提示可以帮助其他开发人员更好地理解代码,特别是在处理大型代码库时。通过清晰地指定变量、函数参数和返回值的数据类型,开发人员可以更快地理解代码的含义和用途,从而更容易维护和修改代码。

如下所示。我们有一个名为 add 的函数,用于将两个数字相加并返回结果。以下是该函数的原始代码:

def add(a, b):
    return a + b

我们发现,该函数没有任何类型提示,因此在调用该函数时,我们必须自己去了解和检查每个参数的类型。这样会导致代码的可读性和可维护性变差,特别是在代码规模较大、涉及多个文件的情况下。为了改善这种情况,我们可以使用类型提示来明确指定每个参数的类型。以下是添加类型提示后的 add 函数的代码:

def add(a: int, b: int) -> int:
    return a + b

现在,我们可以清楚地看到函数 add 的参数和返回值都是整数类型。这使得代码更易于理解,也提高了代码的可靠性。

2 检测类型错误

Python 是一种动态语言,因此变量和函数参数的类型可以在运行时进行更改。但是,这也意味着开发人员容易在代码中引入类型错误。通过使用类型提示,开发人员可以在编译时检测到这些类型错误,并更早地发现和修复它们,从而减少代码错误和调试时间。

mypy是一个用于检查Python类型的静态类型检查器。它可以检测类型注释中的错误以及其他类型的错误。mypy使用说明可以参考:mypy简易教程。mypy需要首先输入以下命令安装:

pip install mypy

然后,在代码中标注变量、函数参数和返回值的类型。运行以下命令:

mypy your_script.py

在上面的示例中,your_script.py是要检查的Python脚本。运行mypy工具后,它将检查Python脚本中的类型错误,并输出错误信息。

3 提供自动补全和文档

许多集成开发环境(IDE)和编辑器都可以使用类型提示来提供自动补全和代码文档。这可以帮助开发人员更快地编写代码,并提供关于函数参数和返回值的信息,以便更好地理解代码。要使用Python类型提示提供自动补全和文档,需要使用一个支持该功能的Python编辑器。比如一些流行的Python编辑器包括vscode、PyCharm和Sublime Text等。

以vscode为例,考虑一个整数相加函数,将结果保存在变量c中。如果加上类型提示,vscode插件将推断变量c的类型为 int,并提供代码补全和代码提示等功能。

此外,还可以使用vscode的autoDocstring生成带有类型提示的文档和注释。

autoDocstring注释代码使用方法如下所示:

按照以上方法,对于有无类型提示的注释结果如下:

def add(a, b):
    """_summary_

    Args:
        a (_type_): _description_
        b (_type_): _description_

    Returns:
        _type_: _description_
    """
    c = a + b
    return c


def add(a: int, b: int) -> int:
    """_summary_

    Args:
        a (int): _description_
        b (int): _description_

    Returns:
        int: _description_
    """
    c = a + b
    return c

2 类型声明

2.1 基本类型

对于Python的内置基本类型 int、float、str 和 byte等,可以直接使用类型本身进行类型提示。如下所示:

# 直接定义
age: int = 1
# 声明后定义
num: float
num = 2.0

def greet(name: str) -> str:
    return f"Hello, {name}!"

def is_even(x: int) -> bool:
    return x % 2 == 0

def encode_data(data: str) -> bytes:
    return data.encode('utf-8')

2.2 嵌套类型

对于容器数据结构,例如 list、tuple、dict 等,也可以直接使用类型本身进行类型提示。如下所示:

items: list = [1, 4.0, "3"]
info: dict = {"name":"john", "age":24}

在Python的容器数据结构中,每个元素都具有其自己的类型。虽然这种方法提供了灵活性,但是内部元素的类型无法受到限制,因此内部元素可以是任何类型(Any)。可以通过Python的typing标准库来声明这些类型及其元素类型。

from typing import List, Tuple, Dict, Set

# 指定my_list变量是一个整数列表
my_list: List[int] = [1, 2, 3, 4]
# 指定my_tuple变量应该是一个按顺序包含整数、字符串和布尔值的元组
my_tuple: Tuple[int, str, bool] = (1, "hello", True)
# 指定了my_dict变量是一个所有键为str类型,所有值为int类型的字典
my_dict: Dict[str, int] = {"apple": 1, "banana": 2, "orange": 3}
# 指定了my_set变量应该是一个浮点数集合
my_set: Set[float] = {1.0, 2.0, 3.0}

2.3 自定义类型

Python也支持对自定义类进行类型提示。下面是一个自定义类的类型提示示例:

class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

def say_hello(person: Person) -> str:
    return f"Hello, {person.name}!"

在上面的代码中,我们定义了一个 Person 类,它有两个属性:name 和 age。在初始函数中,我们使用类型提示指定了这两个属性的类型。接下来,我们定义了一个 say_hello 函数,这个函数的参数是一个 Person 类型的对象,并且返回值是一个字符串。

对于numpy和pandas这种第三方库,也可以通过同样的方法进行类型提示:

import numpy as np
import pandas as pd
import cv2

# numpy
def add_arrays(a: np.ndarray, b: np.ndarray) -> np.ndarray:
    return np.add(a, b)

# pandas
def filter_dataframe(df: pd.DataFrame, column: str, value: float) -> pd.DataFrame:
    return df[df[column] > value]

# opencv,opencv图像本身就是一个numpy数组结构
def resize_image(img: np.ndarray, height: int, width: int) -> np.ndarray:
    return cv2.resize(img, (width, height))

2.4 复合类型

2.4.1 Union和Optional

Python的typing库也提供了Union类型用于表示多种类型中的一种,Optional类型用于表示可选类型。它们可以结合使用,以便更好地表示变量的类型。

例如,如果一个变量可以是整数或字符串类型,那么可以这样定义它的类型:

from typing import Union

def func(x: Union[int, str]) -> None:
    pass

上面的代码中,x的类型为Union[int, str],表示x可以是整数或字符串类型。

如果一个变量可以是整数类型或None类型,那么可以这样定义它的类型:

from typing import Optional

def func(x: Optional[int] = None) -> None:
    pass

Union和Optional类型可以结合使用。例如,如果一个变量可以是整数类型、字符串类型或None类型,那么可以这样定义它的类型:

from typing import Optional, Union

def func(x: Optional[Union[int, str]]) -> None:
    pass

上面的代码中,x的类型为Optional[Union[int, str]],表示x可以是整数类型、字符串类型或None类型。

此外,在Python中,Union[X, Y] 表示变量的类型可以是 X 或 Y。因此,Optional[X] 实际上是 Union[X, None] 的简写形式。这种语法的好处是它可以使代码更简洁,因为我们只需要写一个类型而不是两个。

from typing import Optional, Union

def greet(name: Optional[str]) -> str:
    if name is None:
        return "Hello, stranger!"
    else:
        return f"Hello, {name}!"

def greet2(name: Union[str, None]) -> str:
    if name is None:
        return "Hello, stranger!"
    else:
        return f"Hello, {name}!"

在上面代码中,greet和greets函数是等价的。在第一个函数中,我们使用了 Optional[str] 来表示 name 可以是一个字符串或者是 None。在第二个函数中,我们使用了 Union[str, None] 来达到相同的效果。

2.4.2 Generator和Iterator

在Python中,Generator和Iterator是非常常见的数据类型。Generator是一种函数,可以通过yield语句生成一个迭代器,而Iterator是一种对象,可以用于迭代元素序列。为了提高代码的可读性和可维护性,我们可以使用类型提示来指定Generator和Iterator的类型。

Generator类型提示使用Generator[ReturnType, SendType, ReturnType]语法,其中ReturnType指定返回值类型,SendType指定发送值类型,ReturnType指定生成器的类型。例如,下面是一个简单的Generator类型提示示例:

from typing import Generator

def even_numbers(n: int) -> Generator[int, None, None]:
    for i in range(n):
        if i % 2 == 0:
            yield i

上面的代码中,even_numbers是一个Generator函数,返回类型是Generator[int, None, None],该函数生成一个整数序列,其中每个偶数都是通过yield语句生成的。

Iterator类型提示使用Iterator[ElementType]语法,其中ElementType指定迭代器元素类型。例如,下面是一个简单的Iterator类型提示示例:

from typing import Iterator

class MyIterator:
    def __init__(self):
        self.current: int = 0
        self.max: int = 5

    def __iter__(self) -> Iterator[int]:
        return self

    def __next__(self) -> int:
        if self.current >= self.max:
            raise StopIteration
        else:
            self.current += 1
            return self.current

在上面的代码中,我们对MyIterator类进行了注释。使用了typing模块中的Iterator类来注释__iter__()方法的返回值类型。同时,我们对current和max属性也进行了注释,指定了它们的类型为int。在__next__()方法中,我们指定了返回值类型为int。

2.4.3 Callable

Callable类型提示用于表示一个可调用对象,例如函数、类或对象等。从形式上来看,Callable类型提示接受两个或三个类型提示参数:第一个参数表示函数的参数类型,第二个参数表示函数的返回类型。下面是一个Callable类型提示的例子:

from typing import Callable

def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
    return func(a, b)

def add(a: int, b: int) -> int:
    return a + b

result = apply(add, 3, 4)
print(result) # 输出7

在上面的例子中,apply函数接受一个名为func的参数,该参数是一个Callable类型,它指定了函数的两个整数参数和一个整数返回值。add函数满足这个条件,因此可以传递给apply函数,它会返回add(3, 4)的结果7。

2.4.4 Any和NoReturn

Any类型表示一个任意类型,它可以用于函数参数、函数返回值和变量等。使用Any类型时,我们可以省略类型注释,使变量类型更加灵活。下面是一个使用Any类型的例子:

from typing import Any

def print_value(value: Any) -> None:
    print(value)

print_value("Hello World")  # 输出 "Hello World"
print_value(123)           # 输出 123

在上面的例子中,我们定义了一个print_value函数,它接受一个任意类型的参数value,并将其打印出来。我们可以看到,我们可以将任何类型的值传递给print_value函数,包括字符串和整数。这使得我们的代码更加灵活。

NoReturn类型表示函数不会返回任何值。这个类型通常用于标识那些没有返回值的函数。下面是一个使用NoReturn类型的例子:

from typing import NoReturn

def print_message(message: str) -> NoReturn:
    print(message)
    raise Exception("Error occurred")

print_message("Hello World")  # 输出 "Hello World",然后抛出异常

在上面的例子中,我们定义了一个print_message函数,它接受一个字符串类型的参数message,并将其打印出来。然后,我们手动抛出了一个异常,这意味着函数不会返回任何值。我们可以使用NoReturn类型来明确地表示这一点。

2.4.5 其他

Python还支持更高级的类型提示。例如,可以使用Sequence来指定一个列表,使用TypedDict来指定一个带有特定键和值类型的字典。此外,Python还支持Literal类型提示,可以限制变量只能取特定的常量值。最近,Python3.8版本还增加了Protocol类型提示,允许指定类需要实现哪些方法和属性。这些类型提示用的不多,但是如果需要更精细的类型控制,可以参考官方文档:typing。

2.5 类型提示的别名

在类型提示中使用了过于复杂的类型,可以考虑将其定义为一个类型别名,然后在函数参数、返回值等处使用该类型别名。例如,如果你需要传递一个包含多个字段的字典作为函数参数,你可以使用Dict[str, Union[int, str, List[int]]]来表示该字典的类型。但是,这个类型过于复杂,不易于理解。你可以将其定义为一个类型别名,如下所示:

from typing import Dict, Union, List

MyDict = Dict[str, Union[int, str, List[int]]]

def my_function(my_dict: MyDict) -> int:
    # Function body
    return 1

这样,你就可以在函数参数、返回值等处使用MyDict这个类型别名,使代码更加易读、易懂。

3 参考

  • typing
  • Python 类型提示简介
  • Type Hints 入门教程
  • mypy
  • mypy简易教程
  • autoDocstring

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

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

相关文章

《Netty》从零开始学netty源码(五十六)之MessageSizeEstimator

MessageSizeEstimator 在channel的配置类中有一个属性msgSizeEstimator,它的功能就是用来预估消息的大小,它的赋值过程如下: 接口MessageSizeEstimator只有一个方法newHandle(),它返回的接口handle是MessageSizeEstimator的内部类…

SpringBoot基础篇1(搭建环境+基础配置)

一、SpingBoot入门案例 SpringBoot是用来简化Spring应用的初始搭建以及开发过程。 先快速搭建一个SpringBoot: 创建一个空project,再创建SpringBoot模块。 点击Create,出现以下页面配置成功 创建一个控制器测试一下: RestCo…

Centos8搭建SMB服务

这里以Centos8为例,搭建简易的SMB服务。虚拟机配置:内存8G、存储64G、CPU单核四线程、网络NAT模式跳过虚拟机与系统配置部分,不清楚虚拟机配置以及创建的请查阅其他文档此文章只用于练习用,商业和个人用可以见解Truenas系统 更新…

改进YOLOv5 | C3模块改动篇 | 轻量化设计 |骨干引入高效卷积运算 DSConv: Efficient Convolution Operator

论文地址:https://arxiv.org/pdf/1901.01928v1.pdf 引入了一种卷积层的变体,称为DSConv(分布偏移卷积),其可以容易地替换进标准神经网络体系结构并且实现较低的存储器使用和较高的计算速度。 DSConv将传统的卷积内核分解为两个组件:可变量化内核(VQK)和分布偏移。 通过…

C 高级 /Day 2

#include<stdio.h> int Max_arr(int (*arr)[5],int row,int hang) {int max0;//最大值int k1;//循环行for(int i0;i<hang;i){int k1;//循环列for(int j0;j<row;j){//控制行和列for(int m0;m<hang;m){for(int n0;n<row;n){//如果是第m行的其他的元素&#xf…

MySQL原理(一):逻辑存储结构

前言 从本文开始&#xff0c;我将分享一下近期学习 MySQL 的笔记&#xff0c;其中大部分来源于极客时间的《MySQL实战45讲》、小林coding、以及部分其他博客和书籍。 这次系列文章着重讲 MySQL 的原理部分&#xff0c;主要是用于面试&#xff0c;也就是我们常说的八股&#x…

华为OD机试 - 有效的括号(Java)

一、题目描述 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。…

力扣习题+——单链表

宝子&#xff0c;你不点个赞吗&#xff1f;不评个论吗&#xff1f;不收个藏吗&#xff1f; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的很重要…

Redis 学习笔记

一、redis中的常见数据结构 Redis共有5种常见数据结构&#xff0c;分别字符串&#xff08;STRING)、列表&#xff08;LIST&#xff09;、集合&#xff08;SET)、散列&#xff08;HASH&#xff09;、有序集合&#xff08;ZSET)。 二、redis中字符串(String)介绍 String 类型是…

[ 云计算 华为云 ] 华为云开天 aPaaS:构建高效的企业数字化平台(上)

文章目录 前言一、 什么是 aPaaS1.1 初识 aPaaS 二、华为云开天 aPaaS2.1 华为云服务类型与种类2.1.1 基础 aPaaS2.1.2 行业 aPaaS&#xff08;一&#xff09;工业 aPaaS&#xff08;二&#xff09;政务 aPaaS&#xff08;三&#xff09;电力 aPaaS&#xff08;四&#xff09;矿…

“深圳十大金口碑人物”优必选科技创始人兼CEO周剑获此殊荣

深圳晚报社联合深圳市诚商信用评级有限公司、深圳市诚信营商促进会和中国善网&#xff0c;共同举办了首届“金口碑”评选活动。活动涵盖多个领域&#xff0c;历经多个环节的评定和实地走访&#xff0c;最终有10名个人、20家企业和70家商户成功获得“金口碑人物”、“金口碑企业…

苹果13白屏无法正常开机怎么办?可以尝试这2种解决方法!

iPhone13莫名重启卡在白苹果&#xff0c;iPhone13开机却一直卡在开机画面&#xff0c;无法正常开机启动。 iPhone13出现以上问题&#xff0c;虽然都是处于苹果logo的状态&#xff0c;都可称为白苹果。 苹果13出现白屏、黑屏、白苹果等故障时&#xff0c;我们该怎么进行强制重启…

网络基础知识2—网络

文章目录 1.IP地址1.1概念1.2作用1.3组成1.4格式1.5举例1.6分类1.7特殊的IP 2.子网掩码2.1作用2.2是否是同一网段 3.Mac地址4.网络数据传输—一跳一跳的过程4.1网络节点4.2IP地址和Mac地址的区别 5.网络硬件设备及技术5.1集线器5.2交换机5.3主机5.4ARP缓存表&#xff1a;主机和…

玩机搞机----rom中build.prop文件的修改 优化 删除 开启等等

对于安卓机型系统中的build.prop文件是必不可少的&#xff0c;网络也很多这类的优化教程。但大多都是老机型的解释&#xff0c;今天这个帖子针对一些新版机型build.prop文件的一些操作实例来分析下。友情提示&#xff0c;修改这个文件有风险。严重会进不去系统。而且机型不同。…

Windows11关闭Edge/Chrome浏览器触摸板双指前进后退手势(防止误触切换页面)

编辑了好久的东西&#xff0c;就因为手势误触一下子切换页面了&#xff0c;难受啊&#xff01; Mac版本的设置参考这篇&#xff08;他这个是通过终端命令做的&#xff09;&#xff1a; Mac Chrome浏览器&#xff0c;关闭双指前进、后退手势 我现在身边没有Mac&#xff0c;不知道…

在线UI设计工具都有哪些?如何选择?

做UI设计不仅要阅读UI设计技巧文章&#xff0c;还要掌握好用的UI设计工具&#xff0c;增加UI设计的实践经验&#xff0c;从而熟能生巧&#xff0c;提高UI设计效率。 找到一个好的在线UI设计工具&#xff0c;比如鱼遇到水&#xff0c;就会开启高效的UI设计。因此&#xff0c;掌…

【ONE·C++ || set和map(二):AVL树和红黑树】

总言 主要介绍AVL树和红黑树的部分框架结构和特性 文章目录 总言1、AVL树1.1、基本概念介绍1.2、重要框架与特性实现1.2.1、如何搭建AVL树的结点 &#xff1a;AVLTreeNode&#xff0c;引入三叉链1.2.2、如何搭建AVL树1.2.3、AVL树插入讲解 1.3、AVL树插入1.3.1、step1&#xf…

超越ChatGPT?新发布:“讯飞星火认知大模”到底行不行?

国内又一巨头发布 大语言模型&#xff0c;是 PPT 融资还是真材实料 &#xff1f; 作为程序员&#xff0c;到底面对这一趋势&#xff0c;我们何去何从 &#xff1f; 目录 讯飞星火&#xff0c;5月6日如约而至 一、你真的了解科大讯飞吗&#xff1f; 二、讯飞星火大模型将超越…

C++ 面向对象特征4 多态(Polymorphism)

目录 1、对多态的理解 2、实现多态的例子 3、多态的意义 4、静态联编与动态联编 1、对多态的理解 同一对象可以有多重层级递进身份 在不同的场合中&#xff0c;被外界所关注的是不同的身份&#xff0c;但本质和应有的行为并不会因外界眼光而改变。 比如说我自己 kali-Myon…

Dev C++中出现 undefined reference to XXX 错误的解决方式

出现 undefined reference to XXX 错误的现象&#xff1a; 主函数中调用在其他文件中定义的函数&#xff0c;编译报错&#xff1a;未定义的引用xxx。 原理&#xff1a;编译器在生成可执行文件的过程包括预处理、编译、汇编、链接&#xff0c;这4个过程&#xff0c;这个问题一般…