User:Xyy23330121/Python/函数注释
如同本学习资料第一次提到注释时一样:在编写程序时,程序员会不可避免地忘记之前写的内容。为了让程序员在读已经忘记的函数代码时,可以快速了解函数的内容、使用要点以及可能的、修改函数的方法。需要进行注释。
本章学习的注释,也可以由功能比较强劲的文本编辑器读取、并在使用函数时实时地给程序员以提示。
由于读者在撰写的代码较少时,并没有作注释的必要,从而学习动力可能不足。本章为选学。
可以通过以下方式,写入和输出文档字符串。
def func():
"""什么都不做
本函数仅包含一个 pass 语句。
当使用 if / else / def 等语句时,冒号
的下一行必须是语句组的内容,要进行缩进。
但单独只有缩进也会导致出错。因此,必须
要写入至少一个语句。若希望语句组不执行
任何操作,可以使用 pass 语句来作为语句
组中唯一的语句。
在使用 pass 语句时,应注意能否有更好的
方法。比如 if True: pass; else: do so-
mething的情况。可以直接用 if not True。
"""
pass
print(func.__doc__) #输出文档字符串的内容
输出为:
什么都不做
本函数仅包含一个 pass 语句。
当使用 if / else / def 等语句时,冒号
的下一行必须是语句组的内容,要进行缩进。
但单独只有缩进也会导致出错。因此,必须
要写入至少一个语句。若希望语句组不执行
任何操作,可以使用 pass 语句来作为语句
组中唯一的语句。
在使用 pass 语句时,应注意能否有更好的
方法。比如 if True: pass; else: do so-
mething的情况。可以直接用 if not True。
我们接下来学的类 (class) 也可以使用文档字符串,写入和输出的方法是相同的。使用文档字符串时,应当注意其可读性。
除上面的“文档字符串”以外,类型注解也是一种良好的注释方式。
对于参数的类型注解如果有不了解的地方,可以查阅 Python 文档。如果查阅 Python 文档之后还不了解,那就直接省略注解也是可以的。
类型名 | 含义 |
---|---|
int |
整数 |
float |
浮点数 |
complex |
复数 |
bool |
布尔值 |
list |
列表 |
tuple |
元组 |
str |
字符串 |
dict |
字典 |
set |
集合 |
frozenset |
不可变集合 |
以下示例展示了对参数的类型进行注解,以及设置默认值的方式。该示例还提示了该函数返回值的类型。
def plus(arg1: int, arg2: int = 0) -> int:
return arg1 + arg2
这代表着:plus
函数的参数 arg1
应传入一个 int
类型的值;arg2
有默认值 0
,如果要传入,应传入一个 int
类型的值。plus
函数应返回一个 int
类型的值。
类型注解仅作为标识,对函数运行无影响。如果我们执行:
print(plus(1.1))
输出为:
1.1
尽管类型注解提示了应当给参数传入整数,但传入浮点数时,函数依旧正常运行。而函数的返回值也并非类型注解提示的整数。
右侧表格简单总结了目前学过的一些类型的名称。读者可以查阅 Python 文档,了解更多的内置类型。
关于类型名称,我们将在“类”章节中得到更深刻的了解。
类型注解是函数的一个属性。我们可以用以下方式输出注解:
print(plus.__annotations__)
注解的输出为一个字典:
{'arg1': <class 'int'>, 'arg2': <class 'int'>, 'return': <class 'int'>}
类型注解可以用于静态类型检查器。静态类型检查器会检查 Python 代码中各元素的类型,并对于其中类型不正确的内容进行提示和报错。比如:
def func(s: int) -> None:
s[index]
在静态类型检查器中会提示报错,因为整数类型不支持索引操作。
一些功能强大的文本编辑器会按照类型来提供提示,比如,输入以下内容后:
a = [0, 1] #文本编辑器检查这一行,得知 a 的类型
a.
文本编辑器会自动在后面添加一个下拉的提示框。以提示之后的内容可以写append
、clear
、copy
等。
但这对于函数的参数是没用的,
def func(a):
a.
此时,文本编辑器不会提供任何提示。这是因为文本编辑器不能通过赋值表达式知道函数参数的类型。
但如果我们使用:
def func(a:list): #文本编辑器检查这一行,得知 a 的类型
a.
文本编辑器就能够提供提示了。这在许多情况下很有帮助。
有些类型,尤其是复合类型写起来比较麻烦。此时,我们可以用以下几种方式创建类型别名:
type vector = list[float]
之后,我们就可以使用名称 vector
进行类型注解。
type
语句是 Python 3.12 新增的。为了向下兼容,也可以通过简单赋值语句创建类型别名:
vector = list[float]
我们之前提到过,None
是 Python 中代表“无”的量。实际上,它同时也是一个类型。我们可以用 None
来标记函数没有返回值。例如:
def prtplus(arg1: int, arg2: int = 0) -> None:
print(arg1 + arg2)
该类型代表任意类型。它可以说明函数参数可以传入任意类型,也可以说明函数可以返回任意类型。例如:
from typing import Any
def prttype(arg: Any) -> None:
print(type(arg))
特别的,对于未进行类型注解的参数或返回值,默认使用 typing.Any
作为其参数类型和返回值类型。
Python 提供了多种抽象基类(Abstract Base Class,在 Python 文档中简称为 ABC)。这些基类也可以用于判断类型。
比如,collections.abc.Mapping
表示映射类型,任何具有映射功能的类型,比如字典,都会被判断为 collections.abc.Mapping
的子类型,也就可以用该类型作为标注:
from collections.abc import Mapping
def func(arg: Mapping) -> None: pass
为了让代码的类型在进行检查时尽可能地适用广泛,可以使用这种抽象类型。
对于 collections.abc
提到的“抽象方法”等内容,可能要到类的方法与Python的计算章节才会详细讲解。
可以用|
运算符,表示类型是左右两者之一。
R = int | float #整数或浮点数
C = int | float | complex #整数或浮点数,或复数
也可以用泛型的方法来作标注:
from typing import Union
R = Union[int, float] #整数或浮点数
C = Union[int, float, complex] #整数或浮点数,或复数
序列类型、字典、集合等被称之为容器类型。许多容器类型都支持下标操作,以表示其内部元素的类型。这种下标操作所得到的结果,称之为泛型。
我们可以用以下方式标注“由某个类型的元素”组成的列表:
a = list[int] #以多个整数组成的类型。
b = list[int | None] #以多个“整数或None”组成的类型
类似,可以用 set[int]
来表示由多个整数组成的列表等。
而对于映射结构,比如 dict
,则是用 dict[str, int]
表示“用字符串作索引,得到整数”的字典。
对于 Python 中的大多数容器,类型系统会假定容器中的所有元素都是相同类型的。这表现在代码上,就是 list[ClassName]
等方式最多仅支持一个参数。由此,我们可以总结出泛型的一般形式:
- 一般容器类型:
list[int]
set[int]
等 - 映射容器类型:
dict[str, int]
collections.abc.Mapping[str, int]
等
但元组是一个例外。元组中的元素,在许多代码中并非相同类型,且其位置很关键。所以,我们有以下特例:
可以用以下方式标注“由特定类型元素”组成的元组:
a = tuple[int, str] #有二个元素的元组,第一个元素是整数,第二个元素是字符串。
之所以使用泛型,是因为没有很好的方法对容器中元素的类型进行判断。于是,在输入:
def func(a: list):
a[0].
之后,哪怕使用了功能强大的文本编辑器,也不会弹出任何关于 a[0]
所属类型的提示。
而如果输入:
def func(a: list[complex]):
a[0].
文本编辑器就可以进行提示了。它会提示之后的内容可以写conjugate
、imag
、real
等。
泛型在使用上和构造出泛型的原类型毫无区别。
array = list[int] #列表泛型
a = array('Python') #等同于 a = list('Python')
print(a, type(a)) #输出:['P', 'y', 't', 'h', 'o', 'n'] <class 'list'>
函数就是可调用的类型。我们可以通过以下方式标注可调用的类型。
from typing import Callable
a = Callable[[int], str] #输入整数参数,返回字符串的可调用类型
b = Callable[[int, int], None] #输入两个整数参数,不返回任何值的可调用类型
特别的,用省略号(三个小数点)可以表示任意参数列表。比如:
from typing import Callable
a = Callable[..., str] #输入任意参数列表,返回字符串的可调用类型
利用 type[ClassName]
的方式,可以要求传入的参数或返回值的类型是“类”本身或其子类本身。我们在之前的学习中,已经遇到过“类”对象了。比如:
1 #类型为:int
type(1) #类型为:type[int]
int #类型为:type[int]
在使用时,可以用以下方式:
a = type[int] #类 int 或其子类
b = type[object] #类 object 或其子类,即任意类型