Python强类型编程

news2024/12/22 6:14:44

Python是一门强类型的动态类型语言,具体如下特性:

  • 可以动态构造脚本执行、修改函数、对象类型结构、变量类型
  • 但不允许类型不匹配的操作

第一个例子体现动态性:用字符串直接执行代码,动态构建了一个函数并执行,甚至给函数挂载新的名字。第二个例子体现强类型性:变量都有类型信息,不同类型无适配操作时不允许操作,例如整数和字符串不允许相加
在这里插入图片描述

动态语言 vs 类型提示

因为Python的强类型挂载,但是又不像C++/Java有强类型定义信息(C++11开始也有auto自动推导了),比较容易出错。因此Python也提供了类型标注功能,有了类型标注提示后,就可以在编码时即发现错误。
例如下面一个有标注,一个没有标注的例子;可以看到有标注的例子,IDE/工具都会在编码时即发现潜在与标注不匹配的执行甚至逻辑错误并提示,而无标注时,工具的支持就大打折扣了。
在这里插入图片描述

函数标注(PEP 3107)

标注功能是通过PEP 3107就添加进来了,以函数的标注为例,实际上对函数参数、返回值标注,是放在add.__annotations__变量里面。如图,IDE、工具可以在代码层面静态检查并提示错误,信息非常直观。
在这里插入图片描述

Python强类型检查的策略

既然强类型有这么多好处,并且已经越来越被接受,是不是意味着Python会往强类型语言转型呢?
可以确认不会发生(至少在Python3上),因为Guido很早就在正式文档中阐述了这方面的策略:
可以看到Python的策略是保留了类型检查向后兼容的能力,不会转型为真正的强类型检查语言,但是Python依然会对强类型检查做持续的支持,通过如下金字塔结构来完成,最终达到即享受强类型检查的好处,又保持向后兼容和动态类型语言的灵活性,根据后续的介绍,可以看到,这方面Python还是付出了不少的努力。
在这里插入图片描述

Python类型系统到Py3.7(2018.6)才基本成型

具体来看下Python做了哪些事情来支持强类型检查,如下是一个非常长的(14个)PEP(Python改进建议)的列表和落地情况(图中时间是文档时间+1年左右是实际落地时间),并且在PEP 483开始快速迭代(图中橙色是比较重要的迭代),并且到了Python3.7才真正算是成型。
在这里插入图片描述

Python强类型检查常用场景实践(22个)

典型类型标注

场景:复杂数据结构的标注(使用别名)(PEP 484)

当被标注的类型比较复杂时,可以使用类型别名来简化类型提示标注。(这里直接使用了内置类型[]做标注(PEP 585))
这个例子中servers是一个比较复杂的结构,它的每个成员可以用一个变量(别名)接住后再继续定义,最后用于标注。
在这里插入图片描述

场景:变参类型标注(PEP 484)

Python的变参也支持标注,如下案例解释了如何对变参、命名变参直接标注其值的类型
在这里插入图片描述

场景:类别选择 Union vs. TypeVar(PEP 484)

Python的动态灵活性,允许一个变量的类型可以是多个选择(例如一个add函数允许传入int、long、str类型的变量等),在这种情况下可以Union和TypeVar来定义。两者区别如下:

  • 使用Union定义可能的类型选择: x、y、返回值的类型同一时刻可以不同
  • 使用TypeVar定义一组类型:x、y、返回值的类型同一时刻必须相同
    在这里插入图片描述

场景:泛型类型(PEP 484)

容器下的泛型:TypeVar
泛型在C++/Java中非常普通,Python中也存在这样的情况,例如参数需要是一个列表,但是里面元素类型可以不定。这种情况,可以使用泛型TypeVar。例如下面这个函数接受一个泛型列表,并返回第一个元素。在标注后,错误的使用情况也可以被检查出来。
在这里插入图片描述
当泛型是多个可选类型时,TypeVar也支持,如下例子:
在这里插入图片描述

类下的泛型:Generic

泛型场景比较丰富,类也有泛化需求,例如一个类需要定义泛型时,比较好的方式是,使用Generic并继承它,参考如下案例:
在这里插入图片描述
以上就各种情况的标注做了大概的介绍,可以看到Python对各种类型的标注都可以很好支持,下面具体讲解一下标注的方式。

标注方式

场景6:使用注释(Comments)进行标注(Annotation)(PEP 484)
可以看到,目前为止的标注都是以修改代码才能完成的,这样某种程度上是有一定风险的,因为修改了代码,就意味着可能引入了BUG,哪怕风险不高。这个问题实际PEP已经考虑到了,这并不是Python添加强类型检查的唯一方式。
除了上面的代码方式标注,还可以用注释进行标注。
形式如下:

# type: xxxx 进行标注
注意其中函数的标注方式:
(参数类型列表) -> 返回值类型

这里举一个例子说明:
在这里插入图片描述

场景:前置引用(PEP 484)

强类型检查实际是是非常复杂的(参考C++模板技术与泛型编程),在进行类型标注时,实际的扩展的情况要复杂的多,下面开始讲解一些高阶的强类型标注的场景。
首先看一个经典案例是一个二叉树节点,在进行类型标注是,就需要引用自己,改如何解决?
这种情况下就需要使用前置引用,方式是用字符串代替类型标注。参考下面例子
在这里插入图片描述
有时可以用TypeVar代替,显得更简洁,但请注意和上述overload有一个重要区别,就是入参与返回参数的映射关系丢失了。
在这里插入图片描述

场景:协变(covariant)与逆变(contravariant) PEP 484

在泛型编程中,还有一个比较常见的概念就是协变与逆变(Java泛型编程中常常遇到),如下定义:

协变:

让一个粗粒度接口(或委托)可以接收一个更加具体的接口(或委托)作为参数(或返回值);
例如:老鹰列表赋值给鸟列表

逆变:

让一个接口(或委托)的参数类型(或返回值)类型更加具体化,也就是参数类型更强,更明确。
例如:鸟列表赋值给老鹰列表

这种情况在Python强类型标注也一样存在,例如下面是一个协变的例子,注意使用了参数covariant=True:
在这里插入图片描述

场景:静态duck typing(PEP 544)

Python支持OOP,也支持duck typing,在强类型检查中,duck typing也一样适用,例如一个函数close_resource接受一个参数,要求这个参数必须提供一个特定的方法.close()。这种需求在强类型检查时,也可以支持,我们称之为静态duck typing,相关方案由PEP 544支持。
在这里插入图片描述
通过继承typing.Protocol,构建了一个IResource的静态类型,再使用这个IResource进行标注,之后就可以实现对所有参数是否具备这个IResource定义的方法进行校验。这就是static duck typing。

某种程度上,可以静态duck typing类似于Java的接口概念。

可以有实现,可以被继承
可以继承多个接口,构建一个新接口(参考后面的例子)

但实际类型检查时,不要求被标注对象继承这个IResource,只需要对象的所有成员方法signature匹配Protocol即可
如下是一个多继承的例子:
在这里插入图片描述

场景:泛型静态duck typing

通用的,泛化在静态duck typing也存在,例如约束的方法中的某个参数的类型,需要是泛化的。这种情况,typing.Protocol也是支持。
和前面一样,只需要使用TypeVar定义个泛型类型,再传递给Protocol即可。参考下面样例,这里定义了一个标准可迭代对象的泛型静态duck typing。
在这里插入图片描述
同样的,也支持泛型编程中的协变或逆变:
在这里插入图片描述

有用的标注库

场景:字面量类型(PEP 586)

Python较新的发布,继续发挥其灵活性的特点,不限于借鉴其他语言的强类型机制,还发扬光大,添加许多更灵活有用的功能,例如这个字面量类型。

有了这个功能后,可以做到不修改类型为enum的情况下,限定传递参数。

语法形式:Literal[字面量1, 字面量2, …]

例如下面例子,使用Literal,限定了打开文件的mode字符串的可枚举值,编码期间就可以检查非法的参数:
在这里插入图片描述

场景:typing.Final(PEP 591)

通用的,在Python 3.8版本中引入一个扩展的标注typeing.Final,用于标注变量,这个内置标注非常有用,可以理解为实现了C++语法const的静态检查作用。

  • 指定变量被初始化后无法再被修改、类变量无法被子类修改。
  • 声明为Final的类成员的变量,未初始化的,必须在__init__里面初始化。
    在这里插入图片描述

场景:typing.final(PEP 591)

另一个被引入的就是小写的typing.final,用于标注类,可以理解为实现了Java语法final的静态检查作用。虽然Python本身就可以扩展实现运行时final的作用,但是这里实现了检查期的final,这个官方版本可以说非常的有用。
如下,除了可以修饰类(不能被继承),甚至可以修饰类的方法(不能被重写)

在这里插入图片描述

优化、控制与扩展

场景:关闭静态类型检查

特定情况下,我们也需要关闭静态检查(例如测试或开发中间时),这种情况只需要使用typing.no_type_check修饰函数或类来关闭。但是如果希望关闭对一个装饰器的静态检查的话,需要使用typing.no_type_check_decorator修饰装饰器来关闭。
在这里插入图片描述

场景:新的Hook方法(PEP 560)

因为typing中常常需要使用[]进行传递类型,在定义自己的类型时,可能需要做一些高级定制,因此Python-Core中引入了新的Hook方法__class_getitem__,在传入类型时会自动调用。这样的修改,简化typing的实现方式
在这里插入图片描述

http://www.hzhcontrols.com/new-1263736.html

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

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

相关文章

力扣744.寻找比目标字母大的最小字符(java暴力查找法,二分查找法)

题目描述: 给你一个字符数组 letters,该数组按非递减顺序排序,以及一个字符 target。letters 里至少有两个不同的字符。 返回 letters 中大于 target 的最小的字符。如果不存在这样的字符,则返回 letters 的第一个字符。 [外链…

岭回归(Ridge)不同alpha值对归回结果的影响

对于有些矩阵,矩阵中某个元素的一个很小的变动,会引起最后计算结果误差很大,这种矩阵称为“病态矩阵”。有些时候不正确的计算方法也会使一个正常的矩阵在运算中表现出病态。对于高斯消去法来说,如果主元(即对角线上的…

亚马逊测评:如何有效使用IP和养号设备环境

随着网络科技的崛起,越来越多的本土企业入驻亚马逊电子商务平台上,这导致了对产品评价需求的激增。然而,评价并非随意进行,它需要多方面的资源,并需要密切注意一些重要环节。以下是我分享给大家一些宝贵的知识&#xf…

如何实现敏捷交付中的自动化测试优化

在提及自动化测试的时候,很多人会把工具的使用等同于自动化测试。自动化测试应该是一个策略性的系统化工程,不只有自动化工具。自动化测试要发挥其频繁快速的质量反馈作用,还需要团队从文化和技术上去建设和学习。 提到敏捷交付,…

数据库监控与调优【十二】—— JOIN语句优化

JOIN语句优化-JOIN种类、算法与原理 JOIN的种类 笛卡尔连接(cross join) -- 举例:通过笛卡尔连接查询两张表的结果集和单查两张表的结果集对比 SELECT count( * ) FROM users a CROSS JOIN orders b; SELECT ( SELECT count( * ) FROM user…

SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现

系列文章: SpringBoot Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 文章目录 前端…

微服务: sleuth和zipkin的用处与zipkin安装使用(下)

目录 0. 上篇传送门: 1. 前言简介 mq安装传送门: 微服务: 01-rabbitmq的应用场景及安装(docker) 1.1 Sleuth是一款分布式跟踪解决方案。 1.2 Zipkin是一个开源的分布式跟踪系统。 2. zipkin安装方式 2.1 windows下安装zipkin: 2.1.0 下载jar包位置 2.1.1 下载后,找…

数值计算例题整理

数值计算 一、误差的来源和分类二、有效数字第一个大题(非线性方程组的迭代法)第二个大题(LU分解)第三个大题(牛顿插值法)第四个大题(直线拟合) 一、误差的来源和分类 误差是描述数…

Git 原理和使用

Git 安装 Git是开放源代码的代码托管⼯具,最早是在Linux下开发的。开始也只能应⽤于Linux平台,后⾯慢慢的被移植到windows下,现在,Git可以在Linux、Unix、Mac和Windows这⼏⼤平台上正常运⾏了。 Linux-centos 安装git sudo yu…

8.3 PowerBI系列之DAX函数专题-矩阵Matrix中高亮显示最大最小值

需求 用颜色标量年度最大最小值 用颜色标示折线的最大值最小值 实现 在条件格式–规则–基于字段进行计算 度量值 is_max_min var displayed_data calculatetable( addcolumns( summarize(‘订单表’,‘产品表’[商品次级类别],‘订单表’[订单日…

arcgis栅格影像裁剪--shp

1、打开软件,导入数据,如下: 2、裁剪面形状如下,为shp文件: 3、在arctoolbox中找到"数据管理工具"--"栅格"--"栅格处理"--"裁剪"工具,如下: 4、打开裁…

(ESP32)报错-portTICK_RATE_MS‘ undeclared

(ESP32)报错-portTICK_RATE_MS undeclared 问题详情ESP- IDF未正确设置 问题详情 报错提示 portTICK_RATE_MS undeclared (first use in this function); did you mean portTICK_PERIOD_MS?具体情况 已经引用相关头文件,并且右键后可以大概…

leetcode 2462. Total Cost to Hire K Workers(雇用 K 名员工的总成本)

每次从 开头candidates个 和 末尾candidates个 工人中选择一个cost最小的。 如果有2个工人cost相同,就选index较小的。 每个工人的cost在数组costs里。 直到雇够k个工人。 问雇k个工人需要多少cost. 思路: 可以考虑用一个优先队列,按cost排…

2023开放原子全球开源峰会——一场开发者的盛宴

文章目录 上午场下午场开发者之夜 #“2023我在开源峰会”特别征文# 2023开放原子全球开源峰会,6月11日-13日在北京盛大召开,开幕第一天正好是周六,没什么事情,一大早就过去了,早晨大概7点出发,公交、地铁一…

Docker Desktop 安装使用教程

一、前言 作为开发人员,在日常开发中,我们需要在本地去启动一些服务,如:redis、MySQL等,就需要去下载这些在本地去启动,操作较为繁琐。此时,我们可以使用Docker Desktop,来搭建我们需…

php+mysql期末作业小项目

目录 1、登录界面 2、注册界面 3、主界面 4、学生表界面 5 、查询学生界面​编辑 6、修改学生信息界面​编辑 7、删除学生信息界面 8、添加学生信息界面 9、后台数据库​编辑 一个简单的php➕mysql项目学生信息管理系统,用于广大学子完成期末作业的参考&…

Android Studio导入flutter项目,运行和调试按钮灰色

描述:用android Studio导入flutter项目,运行和调试按钮无法点击并置灰,显示如下 解决方法:检查是否设置如下内容: 1.是否配置了Android SDK ,打开 file > project Structure >project 2.是否配置了F…

【架构】领域驱动设计(DDD)的几种典型架构介绍

文章目录 前言一、专业术语二、架构演变三、限界上下文四、领域驱动设计的四重边界五、整洁分层架构六、六边形架构七、洋葱架构总结 前言 我们生活中都听说了DDD,也了解了DDD,那么怎么将一个新项目从头开始按照DDD的过程进行划分与架构设计呢&#xff…

【Web自动化测试】如何生成高质量的测试报告

运行了所有测试用例,控制台输入的结果,如果很多测试用例那也不能够清晰快速的知道多少用例通过率以及错误情况。 web自动化测试实战之批量执行测试用例场景: 运行 AllTest.py 文件后得到的测试结果不够专业,无法直观的分析测试结果,我们能否…

如何学习和提高CAPL语言编程能力

CAPL是Vector公司开发的,用来配合它的系列产品使用的一款面向过程的语言。CAPL是Communication Access Programming Language的缩写,从字面意思来说,是专门用于通信访问的编程语言。 最初访问CAN总线,现在已扩展到所有的汽车总线…