- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在Python语言发展的过程中,PEP提案发挥了巨大的作用,如PEP 3107 和 PEP 484提案,分别给我们带来了函数注解(Function Annotations)和类型提示(Type Hints)的功能.
PEP 3107:定义了函数注解的语法,允许为函数的参数和返回值添加元数据注解.
PEP 484:按照PEP 3107函数注解的语法,从Python语法层面全面支持类型提示,类型提示可以是内置类型、内置类、抽象基类、types模块中提供的类型和开发人员自定义的类.
另外 PEP 526, PEP 544, PEP 586, PEP 589, PEP 591 这些东西对 PEP 3107 和 PEP 484 进行了补充,比如添加了变量注释,字面量注释这些东西.
需要注意的是,类型提示仅有提示的作用,这里的提示是指用户阅读Python代码的时候的提示,仅在语法层面支持, 对代码的运行没有任何影响,Python 解释器在运行代码的时候会忽略类型提示 ,也就是说,Python的类型提示仅是为了提升代码可读性,一定程度上缓解"动态语言一时爽,代码重构火葬场"的尴尬.
下面将函数注解和类型提示,统称为类型注解.
1、可以使Python拥有部分静态语言的特性,利用类型注解可以实现一种类似类型声明的效果,提升代码的可读性及后续的可维护性.
2、类型注解可以让IDE(如pycharm)像静态语言那样分析我们的代码,及时给我们相应的提示,如下图对比:
3、多多使用类型注解,不仅可以让Python拥有强类型语言的严谨,还能保持Python作为动态类型语言的灵活性.
在声明变量时,变量的后面可以加一个冒号,后面再写上变量的类型,如 int、list 等等,以此实现类型注解.
a: int = 22
b: str = "name"
c: float = 55.5
d: bool = True
e: list = [1, 2, 3]
f: set = {1, 2, 3}
g: dict = {"name": "ming", "age": 22}
h: tuple = (1, 2, 3)
i: bytes = b'world'
j: bytearray = bytearray("world")
函数参数的类型声明就是冒号+类型即可,和普通变量类型声明没区别.
函数返回值的类型声明是用箭头指向具体的类型,如果是返回值有多个,使用元组包裹即可(因为函数的多个返回值就是以元组形式返回的),需要注意的是,箭头左右两边都要留有空格.
def handler(a: int, b: int) -> int:
return a + b
def handler2(a: int, b: int, *args: int) -> int:
return a + b + sum(args)
def handler3(a: int, b: int, *args: int, **kwargs: int) -> (int, str):
return a + b + sum(args) + sum(kwargs.values()), ""
typing模块的加入不会影响程序的运行,也不会报正式的错误,pycharm支持检测基于typing注解的错误,不符合规定类型注解时会出现黄色警告,但不会影响程序运行.
列表、字典、元组等包含元素的复合类型,用简单的 list,dict,tuple 不能够明确说明内部元素的具体类型.
此外,Python本身就是动态类型的语言,如果我们强制使用某种类型,一定程度上会丧失Python作为动态语言的优势,因此 typing 模块提供了一种复合类型注解的语法,即一个参数即可以是类型A,也可以是类型B或者类型C 。
from typing import Dict, List, Set, Tuple, Union
# 字典
d: Dict[str, int] = {"a": 1, "b": 2}
d1: Dict[str, int or str] = {"a": 1, "b": "2"} # 使用or表示支持多个类型
# 列表
l: List[int] = [1, 2, 3]
l1: List[int or str] = [1, 2, "3"]
# 元组
t: Tuple[str, int] = ("a", 1) # 代表了构成元组的第一个元素是 str 类型,第二个元素是 int 类型
t1: Tuple[str, ...] = ("a", "b", "c", "d", "e", "f", "g") # 代表接受多个 str 类型的元素
t2: Tuple[str or int, ...] = ("a", "b", 2) # 代表接受多个 str 或 int 类型的元素
# 集合
s: Set[int] = {1, 2, 3, 4}
s1: Set[Union[int, str, float]] = {1, "2", 3.333, 4} # Union 同 or
TypedDict声明一个字典类型,该类型期望它的所有实例都有一组固定的keys,其中每个key都与对应类型的值关联.
from typing import TypedDict
class Student(TypedDict):
name: str
age: int
height: float
s1: Student = {
"name": "xiao ming",
"age": 22,
"height": 55.5
}
s2: Student = {
"name": "xiao hong",
"age": 21,
}
可以看出,pycharm也会警告我们字典实例中缺失的key.
同时,在我们生成字典实例的时候,pycharm也会给我们key的提示.
类型别名是通过将类型分配给别名来定义的,类型别名可用于简化复杂类型提示.
from typing import Union
Number = Union[int, float]
def process(v: Number) -> Number:
return v
x: Number = 2
y: Number = 2.2
process(x)
process(22) # 类型检查成功,类型别名和原始类型是等价的
使用NewType辅助类来创建不同的类型 。
from typing import NewType
Number = NewType("Number", int)
def process(v: Number) -> Number:
return v
x: Number = Number(22)
process(x)
process(22) # 类型检查异常:Expected type 'Number', got 'int' instead
# 原因就是NewType创建的是原始类型的“子类型”
因此,类型别名 和 NewType 具体使用哪个,要视情况而定,不知道使用哪个,可以先使用类型别名.
当一个方法没有返回结果时,为了注解它的返回类型,我们可以将其注解为 NoReturn.
因为Python 的函数运行结束时隐式返回 None ,这和真正的无返回值是有区别的.
from typing import NoReturn
def process() -> NoReturn:
pass
使用 Optional[] 表示可能为 None 的值 。
from typing import Optional
def handler(x: int) -> Optional[int]:
if x % 2 == 0:
return x
若一个变量类型是可调用函数,则可以用 Callable[[Arg1Type, Arg2Type], ReturnType] 实现类型提示 。
from typing import Optional, Callable
def handler(x: int) -> Optional[int]:
if x % 2 == 0:
return x
def handler2(func: Callable[[int], Optional[int]]):
pass
handler2(handler)
指示相应的变量或函数参数只接收与提供的字面量(或多个字面量之一)等效的值,可以理解为规定了某个参数或变量的所有枚举值.
from typing import Literal, NoReturn
Mode = Literal["r", "w"]
def process(mode: Mode) -> NoReturn:
pass
process("s")
可以看出,pycharm检查出了我们输入的值并不符合字面量规定的值,进而出现了黄色警告.
是一种特殊的类型,每种类型都视为与Any兼容,同样,Any也与所有类型兼容。可以对Any类型的值执行任何操作或方法调用,并将其分配给任何变量。将Any类型的值分配给更精确的类型(more precise type)时,不会执行类型检查,所有没有返回类型或参数类型的函数都将隐式地默认使用Any.
使用Any,说明值是动态类型.
把所有的类型都注解为 Any 将毫无意义,因此 Any 应当尽量少使用 。
from typing import Any
def foo() -> Any:
pass
# 在某些情况下,我们可能并不需要严格区分一个变量或参数到底是列表 list 类型还是元组 tuple 类型
# 可以使用一个更为泛化的类型,叫做 Sequence,其用法类似于 List
class typing.Sequence(Reversible[T_co], Collection[T_co])
# collections.abc.Iterator的泛型版本
# 注释函数参数中的迭代类型时,推荐使用的抽象集合类型
class typing.Iterable(Generic[T_co])
def print_iterable(x: Iterable):
for i in x:
print(i)
# collections.abc.Mapping的泛型(generic)版本
# 注释函数参数中的Key-Value类型时,推荐使用的抽象集合类型
class typing.Mapping(Sized, Collection[KT], Generic[VT_co])
先抛出问题:
假设有一个函数,要求它既能够处理字符串,又能够处理数字。那么你可能很自然地想到了 Union ,如下:
from typing import Union
AddValue = Union[int, str]
def add(a: AddValue, b: AddValue) -> AddValue:
return a + b
if __name__ == "__main__":
print(add(1, 2)) # 类型检查通过,输出 3
print(add("1", "2")) # 类型检查通过,输出 12
print(add("1", 2)) # 类型检查通过,报错 TypeError: can only concatenate str (not "int") to str
在类型检查通过的情况下,我们完成并运行了这段代码,可是代码却报错了! 。
原因就是我们的初衷是数字和数字相加实现求和,字符串和字符串相加实现拼接,没有考虑到字符串与数字混用的问题,从而引发错误.
根据以上问题,我们可以引入泛型来解决这个问题:
from typing import TypeVar
AddT = TypeVar("AddT", int, str)
def add(a: AddT, b: AddT) -> AddT:
return a + b
if __name__ == "__main__":
print(add(1, 2)) # 类型检查通过,输出 3
print(add("1", "2")) # 类型检查通过,输出 12
print(add("1", 2)) # 类型检查失败,pycharm告警 Expected type 'str' (matched generic type 'AddT'), got 'int' instead
""" 通过告警,我们提前发现了混用类型的问题,避免了程序运行时发生异常的可能。 """ 。
泛型很巧妙地 对类型进行了参数化 ,同时又保留了函数处理不同类型时的灵活性.
1、 Python 标准库 typing 类型注解标注 。
2、 Python类型注解,你需要知道的都在这里了 。
最后此篇关于Python类型注解的文章就讲到这里了,如果你想了解更多关于Python类型注解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
注解@CrossOrigin 出于安全原因,浏览器禁止Ajax调用驻留在当前原点之外的资源。例如,当你在一个标签中检查你的银行账户时,你可以在另一个选项卡上拥有EVILL网站。来自EVILL的脚本
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界. 这篇CFSDN的博客文章深入理解Java高级特性——注解由作者收集整理,如果你对这篇文章有兴趣,
概述 在这个快速教程中,我们将探索 Spring 的 @RequestParam 注解。 简单地说,我们可以使用 @RequestParam 从请求中提取查询参数、表单参数甚至文件。我们将讨论如何使用
我有一个关于 Spring @Async 注释的问题。我有一个 Controller 自动连接了一个服务(GnInsuranceDetailsService) @RequestMapping(va
我在使用注释来调用注释所属的方法时遇到了一些麻烦......我将举一个例子: class MyEventHandlers { @handler(id=“1”) public doSom
我是.Net程序员,但是这次我正在从事Java项目,并且遇到了一些困难。这个 java 项目不是我的,它是由其他开发人员开发的,并且使用 Hibernate。 当我运行 Ant 构建器时,我收到此错误
我在 Grails 文档(第 9 章:测试)中读到过这个注解。但是我不明白这是什么... 问题是我需要模拟 GORM 的动态方法,有一种方法可以自动模拟它们,而不必编写我需要的所有方法吗? 最佳答案
这个问题在这里已经有了答案: How to get annotation class name, attribute values using reflection (2 个答案) 关闭 5 年前。
如何了解 Java EE 6 JMS 注释规范支持的所有有效属性集@ActivationConfigProperty Java EE 6 Documentation for @ActivationCo
我认为这是不可能的,但也许我错了。所以我问你,如果可能的话。 ;-) 如果我定义了一个注释,它只接受类引用,它扩展了一些可能的接口(interface)或类: Class serviceIFProv
我正在尝试使用 javax.validation 验证一些 DTO,但似乎注释 @NotEmpty 没有检查参数是否为 null。 这是我的类(class): Person.class public
我是 hibernate 新手,我正在尝试学习它,但在尝试使一对多关系正常工作时遇到了问题。我尝试了几个例子,但似乎没有一个起作用。 有人可以看一下下面的代码并告诉我哪里出了问题吗?我尝试了很多不同的
这个问题已经有答案了: Why doesn't Java offer operator overloading? (17 个回答) 已关闭 9 年前。 每个人都知道 Java 中的简单算术如何用于基元
有人知道如何用 Python 处理这种 XML 注释,这是我第一次看到。 <?link id="752760" resource-uuid="UUID-9f0575a3-1847-1cde-fd
我遇到了这个link这解释了如何继承 bean。假设此示例中的 HelloWorld 类使用 @Component 注释作为 bean 公开,如何创建另一个继承此 bean 的 bean?我可以使用
谁能告诉我这段代码是否: public class OvTester { @Override public int hashCode() { return toStri
我有一个实体,它有一个非键列,我已将其设置为在我的数据库中自动生成。 我不能使用 @GeneratedValue,因为据我所知,它仅适用于关键字段。 在这种情况下,如何指示非键列是自动生成的? 最佳答
所以可能像很多人一样,我通常会临时注释掉代码,主要是为了调试目的。我目前放了类似 **DEBUG** 或任何容易搜索的内容,但我认为让编译器在发现临时注释掉的代码时输出警告(甚至错误)可能很有用。我想
此组件解决的问题是: 「谁」在「什么时间」对「什么」做了「什么事」 本组件目前针对 Spring-boot 做了 Autoconfig,如果是 SpringMVC,也可自己在 xml 初始化 b
配置全局乱码过滤器 参数绑定注解@RequestParam 注解@RequestParam的参数使用说明 获得Restful风格的参数 自定义类型转换器 自定义转换器的开发步骤: 获得Servlet相
我是一名优秀的程序员,十分优秀!