簡述
在 Python 3.x 中,增加了一個新特性 - 函數注釋(Function Annotations),顧名思義,可做為函數額外的注釋來用。
函數注釋是一個可選功能,它允許在函數參數和傳回值中添加任意的中繼資料。無論是 Python 本身還是标準庫,都使用了函數注釋,第三方項目可以很友善的使用函數注釋來進行文檔編寫、類型檢查、或者是其他用途。
| 版權聲明:一去、二三裡,未經部落客允許不得轉載。
為何要引入函數注釋?
在 Python 2.x 中,由于缺少對函數參數和傳回值進行注釋的标準方法,是以很多工具和庫為了填補這一空白,使用了不同的方式:
- 自定義 decorator
- 自定義 docstring 格式
- 向函數對象添加自定義屬性
顯然,由于機制和文法的廣泛差異,這會在一定程度上引起混亂。
為了解決這個問題,Python 3.x 引入了函數注釋(詳見:PEP-3107),旨在提供了一種單一的、标準的方法,來将中繼資料與函數參數和傳回值相關聯。
注意: 注釋是完全可選的。
函數注釋文法
函數注釋包括:
- 參數注釋:以冒号(
)标記:
- 傳回值注釋:以
标記->
文法結構大體如下:
def foo(a: expression, b: expression = 5) -> expression:
在僞文法中,參數看起來像:
identifier [: expression] [= expression]
。也就是說,參數注釋總在其預設值之前。當函數定義被執行時,所有的注釋表達式都被求值,就像預設值一樣。
參數清單後面可以跟一個
->
和一個 Python 表達式。與參數的注釋一樣,在執行函數定義時,将對該表達式求值。
單個注釋
函數注釋可以包含類型、幫助字元串,以及其他更多資訊。
來看一個例子,有一個函數 sum(),接受三個參數 a、b、c,并傳回它們的和。
>>> def sum(a, b: int, c: 'The default value is 5' = 5) -> float:
... return a + b + c
...
其中,第一個參數 a 沒有注釋,第二個參數 b 帶有類型為 int 的注釋,第三個參數 c 帶有一個幫助字元串注釋并且擁有預設值,傳回值用類型 float 來注釋。
調用 sum() 兩次,一次使用 int,一次使用字元串:
>>> sum(1, 2)
8
>>>
>>> sum('Hello', ', ', 'Python!')
'Hello, Python!'
顯然,注釋對函數的執行沒有任何影響。在這兩種情況下,sum() 都做了正确的事情,隻不過注釋被忽略了而已。
通路函數注釋
函數對象有一個名為
__annotations__
的屬性,它是一個映射(dict),用于将每個參數名(key)映射到其相關的注釋(value)。
注意: 映射中有一個特殊的 key,叫做“return”,僅當為函數的傳回值提供注釋時,才會顯示該 key。
回到上述示例,并檢查它的注釋:
>>> type(sum.__annotations__)
<class 'dict'>
>>>
>>> sum.__annotations__
{'c': 'The default value is 5', 'return': <class 'float'>, 'b': <class 'int'>}
之是以選擇 “return”,是因為它不會與任何參數名沖突。“return”是 Python 中的一個關鍵字,任何使用“return”作為參數名的嘗試都會引發 SyntaxError。
多個注釋
倘若,函數注釋中要同時包含類型和幫助字元串,怎麼辦?很容易,可以使用具有兩個 key(例如:type 和 help)的 dict:
>>> def div(a: dict(type=float, help='the dividend'),
... b: dict(type=float, help='the divisor (must be different than 0)')
... ) -> dict(type=float, help='the result of dividing a by b'):
... """Divide a by b"""
... return a / b
...
調用 div():
>>> div.__annotations__
{'a': {'type': <class 'float'>, 'help': 'the dividend'}, 'return': {'type': <class 'float'>, 'help': 'the result of dividing a by b'}, 'b': {'type': <class 'float'>, 'help': 'the divisor (must be different than 0)'}}
>>>
>>> div(5, 2)
2.5
注意: 如果要包含更多的注釋(示例中是 2 個),可以在 dict 中包含更多的
key:value
對。
動态注釋
__annotations__
是函數的一個屬性,類型為 dict。由于 dict 是可變的,這意味着,可以在程式運作時動态地修改注釋。
>>> def sum(a, b) -> 0:
... result = a + b
... sum.__annotations__['return'] += result
... return result
...
>>> sum.__annotations__['return']
0
>>>
>>> sum(1, 2)
3
>>> sum.__annotations__['return']
3
>>>
>>> sum(3, 4)
7
>>> sum.__annotations__['return']
10