
有句话说的好,“动态一时爽,重构火葬场”。因此,python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。例如,在vscode中只要你安装了python相关的插件之后,当你在编写如下的代码的时候,是没有任何提示的。
def fun(data):
data.update({"a": 1})
但是,如果你对data做了注解,那么将会有相应的提示。
def fun(data:Dict[str, int]):
data.update({"a": 1})
这是类型注解带来的好处之一。(如果你是使用Pycharm这样的IDE,那么你不使用类型注解也会有自动提示。)我们最关心的依旧是通过类型注解对动态语言做静态类型检查,来避免一些潜在的错误。
内置类型注解 非容器类型对于非容器类型而言,类型注解的使用是非常简单的。例如:
a:int = 1
b:float = 3.1415926
c:bool = False
d:str = "qwert"
直接在变量后面跟上“:”,然后指明类型即可。
容器类型如果你的只希望指明容器类型本身,那么容器类型注解使用起来非容器类型是类似的。例如:
a:dict = {"a": 1, "q": 123, 123: 456}
b:list = [1, 12.2, 212]
c:tuple = ("qwe", 123)
d:set = set(range(10))
如果你想指定容器内数据详细的数据类型,那么在python3.9之前的版本,需要从typing模块导入相应的注解函数,然后进行注解。例如:
from typing import Dict, List, Optional, Tuple, Set, Union
a:Dict[Union[str, int], int] = {"a": 1, "q": 123, 123: 456}
b:List[Union[int, float]] = [1, 12.2, 212]
c:Tuple[str, int] = ("qwe", 123)
c1:Tuple[Union[int ,str], ...] = (12,'11',33)
d:Set[int] = set(range(10))
e:Optional[str] = None
下面来解释一下Dict, List, Optional, Tuple, Set, Union它们的作用。需要注意的是,这不是函数调用,这里使用[]包括起来,而非().
-
Union表示只要是[]中任意一种类型即可。
参数必须是某种类型,且至少有一个。 联合类型之联合类型会被展平,例如: Union[Union[int, str], float] == Union[int, str, float] 单参数之联合类型就是该参数自身,例如: Union[int] == int # The constructor actually returns int 冗余的参数会被跳过,例如: Union[int, str, int] == Union[int, str] == int | str 比较联合类型,不涉及参数顺序,例如: Union[int, str] == Union[str, int] -
Dict中的第一个值是键的类型,第二个值是值的类型
-
List只能有一个值,因此如果其中包含多种类型,需要使用Union
-
Tuple比较特殊,由于tuple是不可变类型,因此上面
c:Tuple[str, int]写法实际表示tuple中只能有两个元素,且第一个元素是str类型,第二个元素是int类型。但是下一行c1:Tuple[Union[int ,str], ...]使用了省略号来表示比较大的元组 -
Optional的含义实际上和Union[X, None]是一致的。
在python3.9+的版本上,支持内置类型直接进行注解,无需从typing模块导入,简化了注解方式,在python3.7起可以使用from future import annotations来支持内置类型直接注解。如下所示:
a:dict[str, int] = {"abc": 123}
b:list[Union[int, str]] = [123,"123"]
类型别名
类型别名类似于C/C++中的typedef,它的使用可以给代码带来更加明确友好的说明,例如:
Vector_int = List[int] # python3.9之前支持的写法
Vector_str = list[str] # python3.9之后支持的写法
c:Vector_int = [1,2,3,4]
d:Vector_str = ['q', 'w', 'e']
Vector_int就是给List[int]起了个别名;同理,Vector_str就是给list[str]起了个别名。后续就可以使用Vector_int来声明变量的类型。类型别名适合用来简化复杂的类型。例如:
Port = int
Scheme = str
Path = str
URL = Tuple[Scheme, Path, Port]
url:URL = ("https://", "home", 443) # 复杂类型URL
除此之外,typing模块还提供了一个NewType方法,来辅助创建不同类型。例如:
from typing import NewType
int16 = NewType("int16", int) # 将产生一个 int16 类,该类立即返回你传递给它的任何参数。
int32 = NewType("int32", int)
a:int16 = int16(123) # 语句 int16(123) 不会创建一个新的类,也不会引入超出常规函数调用的很多开销。
b:int32 = int32(1234567)
c:int16 = 123 # 无法通过静态检查,因为int16是int的子类。这不是C++,父类指针不能 *** 作子类对象。
注意,使用class来派生NewType创建的类型,是非法的;但是可以使用NewType来继续派生NewType创建的子类。例如:
from typing import NewType
UserId = NewType('UserId', int)
ProUserId = NewType('ProUserId', UserId)
警告:python3.10中NewType 现在是一个类而不是一个函数。在调用 NewType时,会有一些额外的运行时间成本。这个成本将在3.11.0中降低
对于Python而言,一般我们是不会使用NewTpye来产生子类型,更多的可能是使用class去派生内置类型,然后进行 *** 作。例如:
class INT16(int):
"有符号16整形"
def __init__(self, num:int) -> None:
if -32768 <= num < 32767:
super().__init__()
else:
raise Exception("Number out of range")
no:INT16 = INT16(-32768)
print(no)
上面的代码也展示了两种类型注释。一是使用自定义类来进行注释;二是对函数的返回值进行注释(使用-> 类型)。
可调用对象的类型注解使用typing模块提供的Callable[[ArgType], ReturnType]来完成。例如:
def func(a:int, b:float) ->str :
return str(a + b)
add:Callable[[int, float], str] = func #
print(add(1, 2))
add作为一个可调用对象,我们对其进行类型注解。上面这种场景可能不是很常见,更常见的可能是在装饰器这里使用Callable来进行注解。例如:
def outer(f:Callable[[str, int, str], None]) -> Callable[[str, int, str], None]:
def inner(a:str , b: int, c: str) -> None:
print("decorator starting")
f(a, b, c)
print("decorator end")
return inner
@outer
def fun1(name:str, age:int, sex:str) -> None:
print("name:", name)
print("age:", age)
print("sex:", sex)
fun1("Zhao si", 22, "男")
Any类型
Any类型是一种特殊的类型,静态类型检查器会将每种类型视与Any类型兼容。例如:
c:Any = 123
c = "123" # OK
所有没有返回类型或参数类型的函数都将隐式默认为Any注解,当你需要混合动态和静态类型的代码时,Any是一个非常好的选择。
另外,对于没有返回值的函数(特指抛出异常的函数),可以使用NoReturn进行注解。例如:
from typing import NoReturn
def raise_exception(b:bool) -> Union[NoReturn, str]:
if not b:
raise Exception("ERROR")
else:
return "OK"
res:Union[NoReturn, str] = raise_exception(False)
基本上,常用的类型注解就是以上这些了,关于类型注解的更多内容,可以参考typing.
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)