機器學習越來越火,大量的機器學習包都支持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就會提示。

如果傳入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編程,深度學習和自然語言處理的文章。