使用者: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 語句
編輯type vector = list[float]
之後,我們就可以使用名稱 vector
進行類型註解。
簡單賦值語句
編輯type
語句是 Python 3.12 新增的。為了向下兼容,也可以通過簡單賦值語句創建類型別名:
vector = list[float]
特殊類型
編輯None
編輯我們之前提到過,None
是 Python 中代表「無」的量。實際上,它同時也是一個類型。我們可以用 None
來標記函數沒有返回值。例如:
def prtplus(arg1: int, arg2: int = 0) -> None:
print(arg1 + arg2)
typing.Any
編輯該類型代表任意類型。它可以說明函數參數可以傳入任意類型,也可以說明函數可以返回任意類型。例如:
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 或其子类,即任意类型