Python類型標注

機器學習越來越火,大量的機器學習包都支持Python,導致了Python近幾年非常火爆,入手門檻低,編程簡單,概念非常少。越來越多的新手小白加入到Python編程。

Python雖然簡單,但也帶來很多問題。尤其是弱類型一直被詬病,平時在寫代碼時,經常也會模糊參數的類型,導致debug難度增加。

自從Python3.5以來,發(fā)布了typing包,推薦標注類型,并且IDE會檢查類型,讓Python看起來有點靜態(tài)語言的感覺了。本文主要參考Python3.7.5的官方文檔 [1]

常用的類型

常用的幾種類型,如int, float, str, List, Tuple, Dict。接下來看幾個例子:
首先必須從typing中導入類型

from typing import List, Dict, Tuple
def greeting(name: str) -> str:
    return 'Hello ' + name
    
print(greeting(188))

如果你輸入的參數不是str,IDE就會提示。

image

如果傳入List, Tuple, Dict,需要用[]來指定內部基礎類型.

def do_nothing(a: List[int], b: Tuple[int, str], c: Dict[str, int]) -> Dict[str, str]:
    return {'key': 'value'}

# 調用
do_nothing([19], (14, 'some'), {"ha": 10})

除此之外基礎類型是可以相互嵌套的,比如字典的值是列表,列表中存放元組,于是可以這樣標注:

def do_nothing(a: Dict[str, List[Tuple[int, int, int]]], ):
    pass

比較復雜的類型標注用起來并不是很方便,我們可以根據業(yè)務指定別名。比如計算一個點與多個點的距離,List中存放的Tuple是點Point,坐標就是三維的浮點數,于是可以定義別名

Point = Tuple[float, float, float]


def compute_distance(p1: Point, points: List[Point]):
    pass

多種類型

不是多個參數,而是多類型,是輸入參數可能存在多種類型,這種情況在Java中多態(tài)來解決。而Python本身是弱類型,輸入參數沒有強制規(guī)定,這個時候該怎么辦?比如傳入參數可能為int, str, float.typing包給我們提供了辦法,可以用Union來定義:

Union[int, str, float]

輸入參數必須是必須是int, str, float.其中之一。如果不確定數據的類型,可以標示為Any類型,表示任意類型。如果輸入參數可能是None值,也可以用Union定義:

Union[str, None]
# 或者
Optional[str]

函數作為輸入參數

如果函數作為輸入參數,如何標記類型呢?其實也不復雜,函數是callable的類型,同樣指定傳入和傳出參數即可。我們來看一個求和的函數,第一個參數就是函數。add_all只是把所有的元素相加,至于對每個元素做什么操作,取決于傳入的函數了。

def add_all(f: Callable[[int], int], params: List[int]):
    return sum(map(f, params))

print(add_all(lambda x: x**2, list(range(1, 10))))

這里要注意的是函數作為參數,有輸入和輸出值。定義較為麻煩,func: Callable[[int], int],輸入參數內部嵌套了中括號,仔細想想也能明白,如果func: Callable[int, int]定義,那么輸入參數和輸出參數該怎么理解呢?想明白了,你就理解了。

返回生成器

生成器在Python是非常常用的,可以很大提高程序的運行效率。如果需要返回生成器對象該怎么做呢?從typing包中導入Generator.我們來看一下例子,輸入列表list,需要每次返回num個數據塊。

from typing import List, Generator
import math


def get_data(l: List[int], num: int) -> Generator:
    """
    輸入list, 每次按照num個數 返回數據塊
    :param l: list data
    :param num: batch size
    """
    epochs = math.ceil(len(l) / num)

    for epoch in range(epochs):
        yield l[epoch * num:(epoch + 1) * num]


for each in get_data(list(range(98)), 5):
    print(each)

小結

本文分別列舉了常用參數的類型標注方法,同時也給出了多種參數類型,以及函數和生成器作為參數輸入的類型標注方法。參數的類型標注是很重要的,一方面可以幫助你理解每個參數的類型,另一方面也增強了代碼的可讀性。尤其是別人讀到你的代碼,調用起來會清晰很多。更多詳細的說明可以查看官方文檔或者源碼。

覺得我的內容還不錯,可以關注我的微信公眾號:數學編程。定期更新Python編程,深度學習和自然語言處理的文章。


  1. https://docs.python.org/zh-cn/3.7/library/typing.html# ?

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容