python - 类型提示 Type Hints

转自 Python -类型提示 Type Hints - 小菠萝测试笔记 - 博客园 (cnblogs.com)

1|0为什么会有类型提示

  • Python是一种动态类型语言,这意味着我们在编写代码的时候更为自由,运行时不需要指定变量类型
  • 但是与此同时 IDE 无法像静态类型语言那样分析代码,及时给我们相应的提示,比如字符串的 split 方法
def split_str(s): strs = s.split(",")

由于不知道参数 s 是什么类型,所以当你敲 s. 的时候不会出现 split 的语法提示

2|0常用类型提示

typing 是在 python 3.5 才有的模块

2|1常用类型提示

  • int,long,float : 整型,长整形,浮点型;
  • bool,str : 布尔型,字符串类型;
  • List, Tuple, Dict, Set :列表,元组,字典, 集合;
  • Iterable,Iterator :可迭代类型,迭代器类型;
  • Generator:生成器类型;

前两行小写的不需要 import,后面三行都需要通过 typing 模块 import 哦

2|2例子

1|0指定函数参数类型

1|0单个参数

# name 参数类型为 str def greeting(name: str) : return "hello"

1|0多个参数

# 多个参数,参数类型均不同 def add(a: int, string: str, f: float, b: bool or str): print(a, string, f, b)

bool or str:代表参数 b 可以是布尔类型,也可以是字符串

1|0指定函数返回的参数类型

# 函数返回值指定为字符串 def greeting(name: str) -> str: return "hello"

1|0复杂一点的栗子

from typing import Tuple, List, Dict # 返回一个 Tuple 类型的数据,第一个元素是 List,第二个元素是 Tuple,第三个元素是 Dict,第四个元素可以是字符串或布尔 def add(a: int, string: str, f: float, b: bool or str) -> Tuple[List, Tuple, Dict, str or bool]: list1 = list(range(a)) tup = (string, string, string) d = {"a": f} bl = b return list1, tup, d, bl # 不 warn 的调用写法 print(add(1, "2", 123, True)) # 输出结果 ([0], ('2', '2', '2'), {'a': 123}, True)

那指定类型的时候用 list、set、dict、tuple 可不可以呢?

可以是可以,但是不能指定里面元素数据类型

def test(a: list, b: dict, c: set, d: tuple): print(a, b, c, d)

2|3List[T]、Set[T]

只能传一个类型,传多个会报错

a: List[int, str] = [12,"34"] b: Set[int, str] = {12,"23"} print(a) print(b)

换成

a: List[int] = [12,"34"] b: Set[int] = {12,"23"} print(a) print(b)

2|4Dict[T,T]

e: Dict[str, int] = {"as": 123, "643": 34} print(e)

2|5Tuple[T]

1|0可以传入多个

d: Tuple[int, str] = (1, "2") print(d) # 输出结果 (1, '2')

1|0只写一个int,但是赋值两个int

from typing import Tuple, List, Dict, Set d: Tuple[int, str] = (1) print(d)

只写一个 int,赋值两个 int 元素会报 warning

1|0写了两个int,但是赋值多于两个

d: Tuple[int, str] = (1, "2", "2")

不会报错,但是也会有 warning

1|0指定一个类型,对所有元素生效

d: Tuple[int, ...] = (1, 2, 3) d: Tuple[Dict[str, str], ...] = ({"name": "poloyy"}, {"age": "33"})

3|0类型别名

可以将复杂一点类型给个别名,这样好用一些

3|1变量例子

# 别名 vector = List[float] var: vector = [1.1, 2.2] # 等价写法 var: List[float] = [1.1, 2.2]

3|2函数例子

# float 组成的列表别名 vector_list_es = List[float] # 字典别名 vector_dict = Dict[str, vector_list_es] # 字典组成列表别名 vector_list = List[vector_dict] # vector_list 等价写法,不用别名的话,有点像套娃 vector = List[Dict[str, List[float]]] # 函数 def scale(scalar: float, vector: vector_list) -> vector_list: for item in vector: for key, value in item.items(): item[key] = [scalar * num for num in value] print(vector) return vector scale(2.2, [{"a": [1, 2, 3]}, {"b": [4, 5, 6]}]) # 输出结果 [{'a': [2.2, 4.4, 6.6000000000000005]}, {'b': [8.8, 11.0, 13.200000000000001]}]

4|0NewType

可以自定义创一个新类型

  • 主要用于类型检查
  • NewType(name, tp) 返回一个函数,这个函数返回其原本的值
  • 静态类型检查器会将新类型看作是原始类型的一个子类
  • tp 就是原始类型
from typing import NewType UserId = NewType('UserId123', int) def name_by_id(user_id: UserId) -> str: print(user_id) return str(user_id) UserId('user') # Fails type check num = UserId(5) # type: int name_by_id(42) # Fails type check name_by_id(UserId(42)) # OK print(type(UserId(5)))

可以看到 UserId 其实也是 int 类型

5|0Callable

是一个可调用对象类型

5|1查看对象是否可调用

# 返回True或False isinstance(对象, Callable)

例子

# 最简单的函数 def print_name(name: str): print(name) # 判断函数是否可调用 print(isinstance(print_name, Callable)) x = 1 print(isinstance(x, Callable)) # 输出结果 True False

函数是可调用的,所以是 True,而变量不是可调用对象,所以是 False

5|2Callable 作为函数返回值

# Callable 作为函数返回值使用,其实只是做一个类型检查的作用,看看返回值是否为可调用对象 from typing import NewType,Callable def print_name(name: str): print(name) def get_name_return() -> Callable[[str], None]: return print_name vars = get_name_return() vars("test") # 等价写法,相当于直接返回一个函数对象 def get_name_test(): return print_name vars2 = get_name_test() vars2("test")

6|0TypeVar 泛型

6|1任意类型

# 可以是任意类型 T = TypeVar('T') def test(name: T) -> T: print(name) return name test(11) test("aa") # 输出结果 11 aa

6|2指定类型

# 可以是 int,也可以是 str 类型 AA = TypeVar('AA', int, str) num1: AA = 1 num2: AA = "123" print(num1, num2) num3: AA = [] # 输出结果 1 123

7|0Any Type

  • 一种特殊的类型是 Any
  • 静态类型检查器会将每种类型都视为与 Any 兼容,将 Any 视为与每种类型兼容
# Any from typing import Any a = None # type: Any a1 = [] # OK a2 = 2 # OK s = '' # type: str s1 = a # OK def foo(item: Any) -> int: # Typechecks; 'item' 可以是任意类型 print(item) return 1 foo(a) foo(a1) foo(a2) foo(s) foo(s1)

7|1隐式使用 Any

def legacy_parser(text): ... return data # 上述写法等价于下述写法 # 所有没有返回类型或参数类型的函数将隐式默认使用 Any def legacy_parser(text: Any) -> Any: ... return data

8|0Union

联合类型

Union[int, str] 表示既可以是 int,也可以是 str

from typing import Union # vars 变量可以是int也可以是 str 类型 vars: Union[int,str] vars = 1 print(vars) vars = "123" print(vars) # 赋值列表会有warning vars = [] print(vars)

8|1等价写法

vars: Union[int, str] # 等价于 vars: [int or str] vars: Union[int] # 等价于 vars: int

8|2union 等价写法

Union[int] == int # 最终 Union[int] 返回的也是 int 类型
Union[int, str, int] == Union[int, str] # 重复的类型参数会自动忽略掉
Union[int, str] == Union[str, int] # 自动忽略类型参数顺序
Union[Union[int, str], float] == Union[int, str, float] # union 嵌套 union 会自动解包

9|0Optional

可选类型

9|1和默认参数有什么不一样

  • 官方原话:可选参数具有默认值,具有默认值的可选参数不需要在其类型批注上使用 Optional,因为它是可选的
  • 不过 Optional 和默认参数其实没啥实质上的区别,只是写法不同
  • 使用 Optional 是为了让 IDE 识别到该参数有一个类型提示,可以传指定的类型和 None,且参数是可选非必传的
# 可选参数 def foo(arg: int = 0) -> None: ... # 不传 arg 默认取 0 foo()
  • Optional[int] 等价于 Union[int, None]
  • 意味着:既可以传指定的类型 int,也可以传 None

9|2例子

1|0使用 Optional

def foo_func(arg: Optional[int] = None): print(arg) foo_func() foo_func(1) # 输出结果 None 1

1|0使用默认参数的写法

def foo_func(arg: int = None): print(arg) foo_func() foo_func(1) # 输出结果 None 1

这种写法,Pycharm 并不会 warning

1|0重点

Optional[] 里面只能写一个数据类型

# 正确 Optional[str] Optional[List[str]] Optional[Dict[str, Any]] # 错误 Optional[str, int] Optional[Union[str, int, float]]

__EOF__

本文作者😎
本文链接https://www.cnblogs.com/dongye95/p/15427512.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   dongye95  阅读(362)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示