mypy 和 typing

mypy

mypy是一个可以帮助我们检查类型的第三方库,通过 pip insatll mypy 安装,然后执行 mypy <py文件> 即可自动帮我们检测数据类型是否使用正确.例如我们有这样一段代码。

test: int = "Hello World!"

我们期望创建一个int类型的变量, 但我们却给变量赋值了字符串。此时利用mypy检查就会提示我们:test.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment] Found 1 error in 1 file (checked 1 source file)。返回信息告诉了我们不符预期的数据类型,并告知了我们具体文件及行号。

此时我们对上述代码行稍作改动

test: int = 1

我们为变量传入正确的int类型数据。并再次用mypy检查,此次返回的信息为:Success: no issues found in 1 source file

由此可见如果我们需要严格控制数据类型,mypy会是一个不错的检测工具。

typing

在有些情况下我们希望我们的数据类型提示更灵活以应对各种情况,此时就可以使用typing来帮助我们。

  • 注意1:typing是在Python3.5才被加入到标准库中,这意味着您需要保证Python版本至少为3.5
  • 注意2:虽然typing模块提供了类型提示的支持,但它不会对代码的实际执行产生任何影响。它主要用于静态类型检查工具、IDE和其他工具来提供类型推断和类型错误检查支持。

1. List

List 可以表明我们需要一个列表,并且我们可以统一指定列表内元素的数据类型。

from typing import List

test1: List = ["Hello World!", 0, True]	# OK
test2: List[int] = [0, 1, 2]	# OK
test3: List[int] = ["Hello World!", 0, True]	# Fails type check

2. Tuple

当需要传入一个元祖时我们可以使用 Tuple,但 TupleList的使用略有不同,Tuple 可以指定元组内每一个元素的数据类型

from typing import Tuple

test1: Tuple = ("Hello World!", 0, True)	# OK
test2: Tuple[str, int, bool] = ("Hello World!", 0, True)	# OK
test3: Tuple[str, int, bool] = ("Hello World!", 0, True, "spare")	# Fails type check
test4: Tuple[str, int, bool] = ("Hello World!", 0)	# Fails type check

3. Dict & TypedDict

Dict 可以表明我们需要一个字典,并且我们可以统一设置字典内键值对的数据类型。

from typing import Dict

test1: Dict = {"str": "Hello World!"}	# OK
test2: Dict[str, bool] = {"like sports" : True, "like music" : True}	# OK
test3: Dict[str, bool] = {"like sports" : True, 0 : True}	# Fails type check
test4: Dict[str, bool] = {"like sports" : True, "like music" : "True"}	# Fails type check

注意:上述代码段中 [] 内的 str 指的是字典中键的数据类型,bool 指的是值的数据类型。

对于字典的数据类型提示我们其实有更灵活的方式,TypedDict 可以帮助我们自定义一个拥有不同数据类型键值对的字典。

from typing import TypedDict, List

# 方法一
MyType = TypedDict('MyType', {"title": str, "todo": List[int]})

# 方法二(推荐)
class MyType(TypedDict):
	title: str
	todo: List[int]
	
test1: MyType = {"title": "Hello World!", "todo": [1, 2]}	# OK
test2: MyType = {"title": "Hello World!"}	# Fails type check
test3: MyType = {"title": "Hello World!", "todo": [1, 2], "spare": "spare"}	# Fails type check
test4: MyType = {"title": "Hello World!", "changed": [1, 2]}	# Fails type check

用上述的方法一和方法二都可以为字典自定义一个提示数据类型的方法,但如果使用了这两种提示方法就意味着我们必须要在创建字典时包含所有的指定的key。若我们不想如此严格的要求某些key的存在,我们可以设置 total=False注意:我们仍然不可以写入未指定的key)。

from typing import TypedDict, List

class MyType(TypedDict, total=False):
	title: str
	todo: List[int]
	
test1: MyType = {"title": "Hello World!", "todo": [1, 2]}	# OK
test2: MyType = {"title": "Hello World!"}	# OK
test3: MyType = {"title": "Hello World!", "todo": [1, 2], "spare": "spare"}	# Fails type check
test4: MyType = {"title": "Hello World!", "changed": [1, 2]}	# Fails type check

4. Union

当我们输入的参数类型有多种可选项时可以使用 Union

from typing import Union

test1: Union[str, int] = "Hello World!"	# OK
test2: Union[str, int] = 0	# OK
test3: Union[str, int] = 1.0	# Fails type check

从Python3.10开始 Union 被替换为 | 意味着 Union[X, Y] 等价于 X | Y,这样我们意味着甚至都不需要导入typing。

test1: str | int = "Hello World!"	# OK
test2: str | int = 0	# OK
test3: str | int = 1.0	# Fails type check

5. Callable

当你需要表明某个函数的参数是函数时可以使用 Callable 作为类型提示。

from typing import Callable

def fun() -> None:
    return None

def main(fun: Callable) -> None:
    return fun()
    
main(fun())	# OK
main(1)	# Fails type check

6. Any

当数据可以为任何类型的时候可以使用 Any 作为数据提示

from typing import Any

test1: Any = "Hello World!"	# OK
test2: Any = 0	# OK

7. Optional

当函数的参数有默认值,导致参数不是必须要传入的,那么你可以尝试使用 Optional 来做到类型提示

from typing import Optional

def test(value: Optional[int] = None):
	return value

test()	# OK
test(0)	# OK
test("Hello World!")	# Fails type check

从上面的代码我们发现, Optional 作用几乎和其他带参数的数据类型提示等价,例如:value: int = 0
但其实是有些许区别的,假设我们声明参数时为 value: int = None 用静态检查工具去检查代码时会返回错误给我们。而我们为 value 指定数据类型为 Optional[int] 但默认值为 None 经过静态检查工具也不会返回错误。这其实是因为 Optional[X] 本质是等价于 Union[X, None] 的。

8. Sequence

Sequence 所提示的是任何可以被索引的数据: 列表,元祖,字符串等。注意:[] 中只可以指定一个数据类型,意味着在我们传入的列表或者元祖等可索引数据时,内部元素的数据类型需要是统一的。

from typing import Sequence

test1: Sequence[str] = "Hello World!"	# OK
test2: Sequence[str] = ["one", "two", "three"]	# OK
test3: Sequence[str] = ("one", "two", "three")	# OK
test4: Sequence[str] = ["one", "two", 3]	# Fails type check
test5: Sequence[str] = ("one", "two", True)	# Fails type check

9.特殊的玩法

  • 灵活运用 |
    其实可以发现单独的使用类型提示是会遇到限制的,例如当我们设定 test: List[str] 之后我们创建列表时就只能在列表中加入字符串元素,但我们在生产中往往列表不会只包含一种类型的元素。当我们希望列表中既可以有字符串又可以有整型时我们用 | 帮助我们做类型提示。
    from typing import List
    
    test: List[str|int] = ["Hello World!", 0]	# OK
    
  • 自定义数据类型
    上文中我们在使用 TypedDict 时做的其实就是一种自定义类型提示。不仅仅 TypedDict 可以这样做,其他的类型提示方法都可以被自定义为自己的类型提示(注意:只有 TypedDict 需要继承实现)。在特定的情况下使用封装好的类型提示或许可以使项目中参数和变量更直观。
    from typing import List
    
    MyType = List[str]
    
    test1: MyType = ["one", "two"]	# OK
    test2: MyType = ["one", 2]	# Fails type check
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值