Python中typing模块的类型注解 基于typing的具名元组定义方法

一、python的注解

Python 是一种动态语言,在声明一个变量时我们不需要显式地声明它的类型,在给函数传值时我们是不知道参数到底应该传入什么类型的。

这样其实就造成了很多不方便的地方,在某些情况下一些复杂的方法,如果不借助于一些额外的说明,我们是不知道参数到底是什么类型的。

因此,Python 中的类型注解就显得比较重要了。

在 Python 3.5 中,Python PEP 484 引入了类型注解(type hints),

在 Python 3.6 中,PEP 526 又进一步引入了变量注解(Variable Annotations),我们可以这样对函数进行注解

类型和变量注解都只是提供了一种提示,对于运行实际上没有任何影响,你随便传也没关系,不按照注解返回也一点问题没有

不过有了类型注解,一些 IDE 是可以识别出来并提示的,比如 PyCharm 就可以识别出来在调用某个方法的时候参数类型不一致,会飘黄,提示 WARNING

具体的语法是可以归纳为两点:

  • 在声明变量时,变量的后面可以加一个冒号,后面再写上变量的类型,如 int、list 等等。
  • 在声明方法返回值的时候,可以在方法的后面加一个箭头,后面加上返回值的类型,箭头左右两边都要留有空格,如 int、list 等等。

注解举例:

# python的注解
names: list = ['Germey', 'Guido']
version: tuple = (3, 7, 4)
operations: dict = {'show': False, 'sort': True}

 二、typing模块

上面的注解看上去没毛病,但是对于list内部到底是什么类型就没办法知道了,所以需要一种更强类型的注解,可以借助 typing 模块

目前 typing 模块也已经被加入到 Python 标准库中,不需要安装第三方模块,我们直接导入就可以直接使用了

更多参考这里

from typing import List, Tuple, Dict, Set, Union, Callable, Literal, Iterable, NoReturn

list1: List[str] = ['Germey', 'Guido']
list2: List[int or float] = [2, 3.5]
list3: List[List[int]] = [[1, 2], [2, 3]] # 支持嵌套

tuple1: Tuple[int, int, int] = (3, 7, 4)
tuple2: Tuple[str, int, float] = ('Mike', 22, 1.75)

dict1: Dict[str, bool] = {'show': False, 'sort': True}


# Union,联合类型,Union[X, Y] 代表要么是 X 类型,要么是 Y 类型。
def process(func: Union[str, Callable]):
 if isinstance(func, str):
  pass
 elif isinstance(func, Callable):
  func()

# Literal,自定义可选参数,如下表明msg_type变量可选项
msg_type:  Literal['text', 'pic', 'file', 'link', 'code','applet','video_account']

# Iterable,可迭代的,如元组、列表,如下#表明返回值是列表,第一个元素是多个UserMessage组成的列表或元组
UserMessage = Tuple[str, str]
all_boy = Literal[True,  False]
def get_msgs(chat: str='张三', user_type: int=2)-> [Iterable[UserMessage], all_boy, str, int]:
    msgs_list = [('张三','你好'), ('李四','hello'), ('王麻子', '哈哈哈')]
    return [msgs_list , True, '2018-03-03', 3]

# Callable,可调用类型,它通常用来注解一个方法,并且要指明方法的参数和返回值
def date(year: int, month: int, day: int) -> str:
    return f'{year}-{month}-{day}'
def get_date_fn() -> Callable[[int, int, int], str]:
    return date

# NoReturn,没有返回结果
def hello() -> NoReturn:
 print('hello')

有了这样的声明,以后我们如果看到方法的定义,我们就知道传入的参数类型了,如调用 add 方法的时候,我们就知道传入的需要是一个数值类型的变量,而不是字符串类型,非常直观。

但值得注意的是,这种类型和变量注解实际上只是一种类型提示,对运行实际上是没有影响的

三、typing模块的具名元组

 typing 模块里面的具名元组本质上还是调用collections.namedtuple,个人感觉typing好用一点:

1.collections.namedtuple实现具名元组

from collections import namedtuple

# collections的定义方式
Sender = namedtuple('Sender', ['name', 'type', 'company'])
TypedMessage = namedtuple('TypedMessage', ['type', 'value', 'link_info'])
UserMessage = namedtuple('UserMessage', ['name', 'message', 'company'])

2.typing.NameTuple 实现具名元组

from typing import NamedTuple, Literal

# typing的定义方式,本质还是collections的,更清晰,一下就能看出是什么
class Sender(NamedTuple):
    name: str
    type: Literal['user', 'self']
    company: str

class TypedMessage(NamedTuple):
    type:  Literal['text', 'pic', 'file', 'link', 'code','applet','video_account'] #
    value: str
    link_info: list = ['', '', '']# 链接卡片的头部文字、描述文字、图标地址,默认为空

class UserMessage(NamedTuple):
    name: str
    message: TypedMessage  # 自己定义的具名元组类型
    company: str


if __name__ == '__main__':
    sender = Sender('小明', 'user', '百度')
    type_message = TypedMessage('text', '早上好')
    user_message = UserMessage(name=sender.name, message=type_message, company=sender.company)

    print(sender.name, sender.type, sender.company) # 小明 user 百度
    print(type_message.type, type_message.value, type_message.link_info) # text 早上好 ['', '', '']
    print(user_message.name, user_message.message==type_message, user_message.company) # 小明 True 百度

 

posted @ 2022-03-07 15:26  www.pu  Views(413)  Comments(0Edit  收藏  举报