『Python』类型注解

        Python作为一种弱类型语言,由于不像Java、C++这些强类型一样,需要显示声明变量类型,所以在你写完代码后回头再看时,很容易出现看不懂的情况。同时,这种弱类型也会导致IDE的代码补全提示功能无法使用,因此Python引入了类型注解的功能,一定程度上缓解这种不足。下面是我总结的一些类型注解的简单应用,我们并不是要做专家,而是成为一个合格的使用者,所以只列举常用到的语法。

1. 基本用法

        类型注解是用于描述定义的变量是什么类型的,一般在变量后面加上冒号,然后把这个变量的类型写在后面,特别地,函数的返回值类型是定义在参数列表之后,冒号之前。

def func(var: para_type = 3) -> return_type:
		pass
	
class B(object):
   	def __init__(self):
       		self.t: para_type = 1
	
a: para_type = 2	

2. 注解类型

2.1 原子类型

        就是一些built-in的类型,如int, float, complex, bool, str, None, list, tuple, set, dict,不过后面四个作为注解太弱势了,我们只知道变量是什么类型,但是它的元素类型是啥我们无法得知,这时候我们就需要借助typing模块

2.2 容器类型

2.2.1 List

List,列表,是 list 的泛型,基本等同于 list,其后紧跟一个方括号,里面代表了构成这个列表的元素类型

from typing import List
name: List[str] = [3, "亚索", "瑞雯", "菲奥娜"]

另外还可以嵌套声明都是可以的:

var: List[List[int]] = [[1, 2], [2, 3]]

2.2.2 Tuple

Tuple,元组,是 tuple 的泛型,其后紧跟一个方括号,方括号中按照顺序声明了构成本元组的元素类型,如 Tuple[X, Y] 代表了构成元组的第一个元素是 X 类型,第二个元素是 Y 类型

from typing import Tuple
info: Tuple[str, int, float] = ("樱木花道", 18, 183.0)

同样地也可以像List一样使用类型嵌套

2.2.3 Dict & Mapping

Dict,字典,是dict的泛型;Mapping,映射,是 collections.abc.Mapping 的泛型。根据官方文档,Dict 推荐用于注解返回类型,Mapping 推荐用于注解参数。它们的使用方法都是一样的,其后跟一个中括号,中括号内分别声明键名、键值的类型

from typing import Dict, Mapping
d: Dict[str, int] = {"1": 1, "2": 2}
m: Mapping[str, int] = {"1": 1, "2": 2}

2.2.4 Set & AbstractSet

Set,集合,是 set 的泛型;AbstractSet,是 collections.abc.Set 的泛型。根据官方文档,Set 推荐用于注解返回类型,AbstractSet 用于注解参数。它们的使用方法都是一样的,其后跟一个中括号,里面声明集合中元素的类型

from typing import Set, AbstractSet
num: Set[int] = {1, 2, 3}
flag: AbstractSet[bool] = {True, False}

2.2.5 Sequence

Sequence,是 collections.abc.Sequence 的泛型,在某些情况下,我们可能并不需要严格区分一个变量或参数到底是列表 list 类型还是元组tuple 类型,我们可以使用一个更为泛化的类型,叫做 Sequence,其用法类似于 List

from typing import Sequence
msgs: Sequence[str] = ["我", "爱", "你"]

2.3 其他类型

2.3.1 NoReturn

NoReturn,当一个方法没有返回结果时,为了注解它的返回类型,我们可以将其注解为 NoReturn

from typing import NoReturn
def show() -> NoReturn:
	 print("test NoReturn")

2.3.2 Any

Any,是一种特殊的类型,它可以代表所有类型,静态类型检查器的所有类型都与 Any 类型兼容,所有的无参数类型注解和返回类型注解的都会默认使用 Any 类型,也就是说,下面两个方法的声明是完全等价的:

from typing import Any
def add(a):
	return a + 1

def add(a: Any) -> Any:
	return a + 1

特别地,有一个类型注解是AnyStr = TypeVar('AnyStr', str, bytes),指所以字符串类型,包括二进制字符串

2.3.3 Callable

Callable,可调用类型,它通常用来注解一个方法,Callable 在声明的时候需要使用 Callable[[Arg1Type, Arg2Type, ...], ReturnType] 这样的类型注解,将参数类型和返回值类型都要注解出来

from typing import Callable, NoReturn
def show(msg: str) -> NoReturn:
	print(msg)

def get_msg(msg: str, func: Callable[[str], NoReturn]) -> NoReturn:
	func(msg)

2.3.4 Union

Union,联合类型,Union[X, Y] 代表要么是 X 类型,要么是 Y 类型

2.3.5 Optional

Optional,意思是说这个参数可以为空或已经声明的类型,即 Optional[X] 等价于 Union[X, None],注意,只能是一个类型,Optional[X, Y]是错的,但值得注意的是,这个并不等价于可选参数,当它作为参数类型注解的时候,不代表这个参数可以不传递了,而是说这个参数可以传为 None

2.3.6 Generator

如果想代表一个生成器类型,可以使用 Generator,它的声明比较特殊,其后的中括号紧跟着三个参数,分别代表 YieldType、SendType、ReturnType

from typing import Generator
def echo_round() -> Generator[int, float, str]:
	sent = yield 0
	while sent >= 0:
  			 sent = yield round(sent)
	return 'Done'

当然很多情况下,生成器往往只需要 yield 内容就够了,我们是不需要 SendType 和 ReturnType 的,可以将其设置为空Generator[int, None, None]

2.3.7 Iterable & Iterator

from typing import Iterable, Iterator
def func(a: Iterator[int], b: Iterable[float]):
	print(a, b)

这个实际上指的就是可迭代类型和迭代器类型,后面中括号内的是迭代的元素的类型

2.4 自定义类型

2.4.1 类型别名

直接上示例,其实就是把定义好的类型注解取个名字

from typing import List
Vector = List[float]
def scale(scalar: float, vector: Vector) -> Vector:
	 return [scalar * num for num in vector]

2.4.2 TypeVar

TypeVar,我们可以借助它来自定义兼容特定类型的变量,比如有的变量声明为 int、float、None 都是符合要求的,实际就是代表任意的数字或者空内容都可以,其他的类型则不可以,比如列表 list、字典 dict 等等,像这样的情况,我们可以使用 TypeVar 来表示
例如一个人的身高,便可以使用 int 或 float 或 None 来表示,但不能用 dict 来表示,所以可以这么声明:

from typing import TypeVar
height = 1.75
Height = TypeVar('Height', int, float, None)
def get_height() -> Height:
	return height

2.4.3 NewType

NewType,我们可以借助于它来声明一些具有特殊含义的类型,例如像 Tuple 的例子一样,我们需要将它表示为 Person,即一个人的含义,但但从表面上声明为 Tuple 并不直观,所以我们可以使用 NewType 为其声明一个类型,如

from typing import NewType, Tuple
Person = NewType('Person', Tuple[str, int, float])
person = Person(('Mike', 22, 1.75))

【注】这个与直接取别名是有差别的,上面定义了新的类型Person,它可以用来类似创建对象的应用person = Person(('Mike', 22, 1.75)),但是如果直接使用别名,如Person=Tuple[str, int, float]则不能这样。

2.4.4 Generic

  • 泛型函数
from typing import Sequence, TypeVar
T = TypeVar('T')  # 申明类型变量
def first(l: Sequence[T]) -> T:  # Generic function
	return l[0]
  • 泛型类
from typing import TypeVar, Generic, List
T = TypeVar('T', int, float)

class Queue(Generic[T]):
 	def __init__(self, l: List[T]):
  	 	self.queue = l

q = Queue([1, 2, 3])
q = Queue[float]([1, 2, 3])

【注】

  1. 这里,Generic[T]还可以增加泛型参数的,如Generic[T, S],但是要注意参数的名字不能一样
  2. 泛型也可以多继承:class LinkedList(Sized, Generic[T])
  3. 从泛型类继承时,某些类型变量可能是固定的:
    from typing import TypeVar, Mapping
    T = TypeVar('T')
    class MyDict(Mapping[str, T]):
    	pass
    
    这里MyDict继承泛型类时,固定了一个参数类型是str
  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值