Python 类型声明 / 类型提示(type hints)Python 类型声明 / 类型提示(type hints)Python 类型声明 / 类型提示(type hints)Python 类型声明 / 类型提示(type hints)
  • 首页
  • 博客
  • 文件
  • 书签
  • 分析
  • 登录
Search
Generic filters

Python 类型声明 / 类型提示(type hints)

Published by admin at 2022年5月4日
Categories
  • Python
Tags
1. 概述

我们都知道,Python是动态编程语言(Dynamic Programming Language)。在Python中不需要对变量进行类型声明,一个变量也可以被赋值为不同的类型。如

a = 3              # 定义a这个变量时不需要进行类型声明
a = "a string"     # a一开始被定义为整数3,又可以别定义为一个字符串

与此类似的还有JavaScript,PHP等。和他们相对应的就是静态语言(Static Programming Language),如C、C++和JAVA。在静态语言中需要对变量以及函数的返回值进行严格的类型声明,如

#include 

int add(int x, int y) // 对函数的返回值以及参数进行了类型声明
{
    int result;    // 新的变量也要进行类型声明
    result = x + y;
    return result;
}

而如果在Python中,就随意多了(如下代码所示),该函数不仅可以用于int + int,float + float,甚至可以用于str + str。

def add(x, y):
    result = x + y
    print(result)
    return result 

add(1, 2)                   # int + int, output: 3
add(1.2, 2.1)               # float + float, output: 3.3
add("have a ", "try!")      # str + str, output: have a try!
1.1 Python中的“类型声明”情况一:类型提示

但是在Python 3.5中加入了“类型声明”的功能,官方文档叫类型提示(type hints)[1]。这样函数就可以写成如下形式,但是在实际运行的时候你会发现一个问题:虽然做了类型提示,但是函数本身并不会对输入的参数进行类型检查。也就是说,除了类型声明的int + int情况,其他情况如float + float和str + str依然适用,并不会报错!

def add(x: int, y: int) -> int:
    result = x + y
    print(result)
    return result 

# 虽然做了类型提示,但并不影响以下代码的执行
add(1, 2)                   # int + int, output: 3
add(1.2, 2.1)               # float + float, output: 3.3
add("have a ", "try!")      # str + str, output: have a try!
1.2 Python中的“类型声明”情况二:变量注解

除了以上的例子,在Python 3.6中继续加入了变量注解(variable annotations)的功能[2],变量注解的格式如下:

# 以下两行是完全等价的
age: int; age = 18
age: int = 18

但是如果你进行如下赋值,你会发现,Python并不会报错,和没有进行变量注解没什么区别。

# 以下两行是完全等价的
age: int = "I am a string!"

print(age)

既然类型提示和变量注解都不会对类型进行检查和报错,那意义何在呢?

2. Python中“类型声明”的意义何在?

其实在官方文档的用词中已经给出了答案,即提示(hints)和注解(annotations),也就是说这些“类型声明”仅仅起到了提示和注解的作用。这么做有三方面好处:

2.1 方便程序员阅读代码
2.2 方便IDE进行代码提示(如下图所示);
code对输入参数的类型和返回值的类型进行了提示
2.3 通过mypy进行类型检查

你也可以通过mypy进行类型检查,如

# demo.py
def add(x: int, y: int) -> int:
    result = x + y
    print(result)
    return result 

add("have a ", "try!") 

检查方法及结果如下:

$ mypy demo.py 
demo.py:6: error: Argument 1 to "add" has incompatible type "str"; expected "int"
demo.py:6: error: Argument 2 to "add" has incompatible type "str"; expected "int"
Found 2 errors in 1 file (checked 1 source file)
3. typing与“类型声明”的更多语法

typing模块中的可导出内容如下,我对其中部分内容进行具体说明。

Typing模块中的可导出内容
3.1 Tuple
from typing import Tuple

t1: Tuple = (1, 2, 3,)                          # 声明t1为元组
t2: tuple[int, ...] = (1, 2, 3,)              # 声明t2为整数组成的元组
# t3: Tuple[int] = (1, 2, 3,)                   # 错误用法,会报错!
t4: Tuple[int, int, int] = (1, 2, 3,)         # 声明t2为3个整数组成的元组
t5: Tuple[int, str, float] = (1, "2", 3.1,)   # 声明t5为int, str, float三个元素组成的元组
3.2 List
from typing import List

l1: List = [1, 2, 3]                        # 声明t1为元组
l2: List[int] = [1, 2, 3]                   # 声明l2为整数组成的元组
# l3: List[int, str, float] = [1, "2", 3.1] # 错误用法,会报错!
3.3 Dict
from typing import Dict

d1: Dict = {"a": 1}                   # 声明d1为字典
d2: Dict[str, int] = {"a": 1}         # 声明d2为字典,且键为str,值为int
3.4 Set
from typing import Set

s1: Set = {1, 2, 3}             # 声明s1为集合
s2: Set[int] = {1, 2, 3}        # 声明s2为int组成的集合
3.5 Union
from typing import List, Union

# 声明l1为列表,且列表中的元素为int,str和float中一种
l1: List[Union[int, str, float]] = [1, "2", 3.1]
3.6 Any

Any的意思是该变量可以是任何类型,包括None。既然可以是任何类型,那Any的意义何在呢?答案是:当对元组内的每个元素都做类型声明,而其中一个元素可以是任何类型的时候,Any就派上用场了。

from typing import Any, Tuple

# 变量可以为任何类型,包括None
a: Any = None

# Used as an escape hatch
l: Tuple[(int, Any, str)] = (1, None, "test")
3.7 Optional

Optional常用语函数传参,代表该参数可无。

from typing import Optional

# arg参数可无,若有则声明为int型
def foo(arg: Optional[int] = None) -> str:
    print(arg)
    return "Demo"

foo()       # output: None
foo(3)      # output: 3
3.8 Callable

Callable指可调用类型,通常指函数,Callable[[X, Y], Z]中[X, Y]指传入参数的类型,Z指的是返回参数的类型,如

from ast import Call
from typing import Callable

def add(x: int, y: int) -> int:
    return x + y

f: Callable[[int, int], int] = add

匿名函数中由于特殊的语法格式,无法进行类型声明。但是可以通过使用Callable进行类型声明,如

from ast import Call
from typing import Callable

# 匿名函数
add = lambda x, y: x + y    
# 无法直接对匿名函数中的参数和返回值进行类型声明, 会报错
# add = lambda x: int, y: int: x + y: int 

# 可通过Callable解决上述问题
add: Callable[[int, int], int] = lambda x, y: x + y 

add(1, 2)
参考
^typing — Support for type hints https://docs.python.org/3/library/typing.html
^PEP 526 – Syntax for Variable Annotations https://peps.python.org/pep-0526/

发表回复 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

Categories

  • 猫
  • Python
  • MySQL
  • Django
  • Html/CSS
  • JavaScript
  • Vue
  • RegExp
  • php
  • Practice
  • Virtualization
  • Linux
  • Windows
  • Android
  • NAS
  • Software
  • Hardware
  • Network
  • Router
  • Office
  • WordPress
  • SEO
  • English
  • Games
  • Recipes
  • living
  • Memorandum
  • Essays
  • 未分类

归档

©2015-2022 Alaica Blog support@alaica.com