天天看點

Python 函數注釋

簡述

在 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