py3筆記19:typing類型注解

常見數(shù)據(jù)類型:str,int,Tuple,List,Dict

在聲明變量類型時(shí)认臊,變量后方緊跟一個(gè)冒號(hào),冒號(hào)后面跟一個(gè)空格锄奢,再跟上變量的類型失晴。
在聲明方法返回值的時(shí)候,箭頭左邊是方法定義拘央,箭頭右邊是返回值的類型涂屁,箭頭左右兩邊都要留有空格。

def get_sum(i: int) -> str:
    return str(i)
  • 利用 mypy 即可檢查出 Python 腳本中不符合類型注解的調(diào)用情況
  • 推薦使用 attrs 這個(gè)庫(kù)來(lái)聲明一些具有表征意義的類灰伟。

typing模塊

標(biāo)準(zhǔn)庫(kù)
借助于 typing 模塊了拆又,它提供了非常 “強(qiáng) “的類型支持儒旬,
List[str]Tuple[int, int, int]則可以表示由 str 類型的元素組成的列表和由 int 類型的元素組成的長(zhǎng)度為 3 的元組

from typing import List, Tuple, Dict

names: List[str] = ["1", 2]  # Expected type 'list[str]', got 'list[int]' instead=>第1個(gè)元素str則正常
ages: Tuple[str, int] = (1, "3")  # Expected type 'tuple[str, int]', got 'tuple[int, str]' instead
student: Dict[int, str] = {12: [12], "123": 12}  # Expected type 'dict[int, str]', got 'dict[str, list[int]]' instead
# Expected type 'dict[int, str]', got 'dict[Union[int, str], Union[list[int], int]]' instead

classs = List[str or int] = [["ba"], [1]]

Tuple

Dict帖族、字典栈源,是 dict 的泛型;

Mapping竖般,映射甚垦,是 collections.abc.Mapping 的泛型。
根據(jù)官方文檔涣雕,Dict 推薦用于注解返回類型艰亮,Mapping 推薦用于注解參數(shù)。它們的使用方法都是一樣的挣郭,其后跟一個(gè)中括號(hào)迄埃,中括號(hào)內(nèi)分別聲明鍵名、鍵值的類型

set

Set兑障、集合侄非,是 set 的泛型;AbstractSet流译、是 collections.abc.Set 的泛型彩库。根據(jù)官方文檔,Set 推薦用于注解返回類型先蒋,AbstractSet 用于注解參數(shù)骇钦。它們的使用方法都是一樣的,其后跟一個(gè)中括號(hào)竞漾,里面聲明集合中元素的類型

NoReturn

NoReturn眯搭,當(dāng)一個(gè)方法沒有返回結(jié)果時(shí),為了注解它的返回類型业岁,我們可以將其注解為 NoReturn

Any

Any鳞仙,是一種特殊的類型,它可以代表所有類型笔时,靜態(tài)類型檢查器的所有類型都與 Any 類型兼容棍好,所有的無(wú)參數(shù)類型注解和返回類型注解的都會(huì)默認(rèn)使用 Any 類型

原理類似于 object,所有的類型都是 object 的子類允耿。但如果我們將參數(shù)聲明為 object 類型借笙,靜態(tài)參數(shù)類型檢查便會(huì)拋出錯(cuò)誤,而 Any 則不會(huì)较锡,具體可以參考官方文檔的說(shuō)明:https://docs.python.org/zh-cn/3/library/typing.html?highlight=typing#the-any-type业稼。

TypeVar

TypeVar,我們可以借助它來(lái)自定義兼容特定類型的變量蚂蕴,比如有的變量聲明為 int低散、float俯邓、None 都是符合要求的,實(shí)際就是代表任意的數(shù)字或者空內(nèi)容都可以熔号,其他的類型則不可以稽鞭,比如列表 list、字典 dict 等等引镊,我們可以使用 TypeVar 來(lái)表示川慌。 例如一個(gè)人的身高,便可以使用 int 或 float 或 None 來(lái)表示祠乃,但不能用 dict 來(lái)表示,所以可以這么聲明:

height = 1.75
Height = TypeVar('Height', int, float, None)
def get_height() -> Height:
 return height

這里我們使用 TypeVar 聲明了一個(gè) Height 類型兑燥,然后將其用于注解方法的返回結(jié)果亮瓷。

NewType

NewType,我們可以借助于它來(lái)聲明一些具有特殊含義的類型降瞳,例如像 Tuple 的例子一樣嘱支,我們需要將它表示為 Person,即一個(gè)人的含義挣饥,但但從表面上聲明為 Tuple 并不直觀除师,所以我們可以使用 NewType 為其聲明一個(gè)類型,如:

Person = NewType('Person', Tuple[str, int, float])
person = Person(('Mike', 22, 1.75))

這里實(shí)際上 person 就是一個(gè) tuple 類型扔枫,我們可以對(duì)其像 tuple 一樣正常操作汛聚。

Callable

Callable,可調(diào)用類型短荐,它通常用來(lái)注解一個(gè)方法倚舀,比如我們剛才聲明了一個(gè) add 方法,它就是一個(gè) Callable 類型:

print(Callable, type(add), isinstance(add, Callable))

運(yùn)行結(jié)果:
True

在這里雖然二者 add 利用 type 方法得到的結(jié)果是 function忍宋,但實(shí)際上利用 isinstance 方法判斷確實(shí)是 True痕貌。 Callable 在聲明的時(shí)候需要使用 Callable[[Arg1Type, Arg2Type, ...], ReturnType] 這樣的類型注解,將參數(shù)類型和返回值類型都要注解出來(lái)糠排,例如:

def date(year: int, month: int, day: int) -> str:
 return f'{year}-{month}-{day}'

def get_date_fn() -> Callable[[int, int, int], str]:
 return date

這里首先聲明了一個(gè)方法 date舵稠,接收三個(gè) int 參數(shù),返回一個(gè) str 結(jié)果入宦,get_date_fn 方法返回了這個(gè)方法本身哺徊,它的返回值類型就可以標(biāo)記為 Callable,中括號(hào)內(nèi)分別標(biāo)記了返回的方法的參數(shù)類型和返回值類型乾闰。

Union

Union唉工,聯(lián)合類型,Union[X, Y] 代表要么是 X 類型汹忠,要么是 Y 類型淋硝。 聯(lián)合類型的聯(lián)合類型等價(jià)于展平后的類型:

Union[Union[int, str], float] == Union[int, str, float]

僅有一個(gè)參數(shù)的聯(lián)合類型會(huì)坍縮成參數(shù)自身雹熬,比如:

Union[int] == int

多余的參數(shù)會(huì)被跳過(guò),比如:
Union[int, str, int] == Union[int, str]
在比較聯(lián)合類型的時(shí)候谣膳,參數(shù)順序會(huì)被忽略竿报,比如:
Union[int, str] == Union[str, int]

這個(gè)在一些方法參數(shù)聲明的時(shí)候比較有用,比如一個(gè)方法继谚,要么傳一個(gè)字符串表示的方法名烈菌,要么直接把方法傳過(guò)來(lái):

def process(fn: Union[str, Callable]):
 if isinstance(fn, str):
 # str2fn and process
 pass
 elif isinstance(fn, Callable):
 fn()

這樣的聲明在一些類庫(kù)方法定義的時(shí)候十分常見。

Optional

Optional花履,意思是說(shuō)這個(gè)參數(shù)可以為空或已經(jīng)聲明的類型芽世,即 Optional[X] 等價(jià)于 Union[X, None]。 但值得注意的是诡壁,這個(gè)并不等價(jià)于可選參數(shù)济瓢,當(dāng)它作為參數(shù)類型注解的時(shí)候,不代表這個(gè)參數(shù)可以不傳遞了妹卿,而是說(shuō)這個(gè)參數(shù)可以傳為 None旺矾。 如當(dāng)一個(gè)方法執(zhí)行結(jié)果,如果執(zhí)行完畢就不返回錯(cuò)誤信息夺克, 如果發(fā)生問題就返回錯(cuò)誤信息箕宙,則可以這么聲明:

def judge(result: bool) -> Optional[str]:
 if result: return 'Error Occurred'

Generator

如果想代表一個(gè)生成器類型,可以使用 Generator铺纽,它的聲明比較特殊柬帕,其后的中括號(hào)緊跟著三個(gè)參數(shù),分別代表 YieldType狡门、SendType雕崩、ReturnType,如:

def echo_round() -> Generator[int, float, str]:
 sent = yield 0
 while sent >= 0:
 sent = yield round(sent)
 return 'Done'

在這里 yield 關(guān)鍵字后面緊跟的變量的類型就是 YieldType融撞,yield 返回的結(jié)果的類型就是 SendType盼铁,最后生成器 return 的內(nèi)容就是 ReturnType。 當(dāng)然很多情況下尝偎,生成器往往只需要 yield 內(nèi)容就夠了饶火,我們是不需要 SendType 和 ReturnType 的,可以將其設(shè)置為空致扯,如:

def infinite_stream(start: int) -> Generator[int, None, None]:
 while True:
 yield start
 start += 1

案例實(shí)戰(zhàn)

接下來(lái)讓我們看一個(gè)實(shí)際的項(xiàng)目肤寝,看看經(jīng)常用到的類型一般是怎么使用的。 這里我們看的庫(kù)是 requests-html抖僵,是由 Kenneth Reitz 所開發(fā)的鲤看,其 GitHub 地址為:https://github.com/psf/requests-html,下面我們主要看看它的源代碼中一些類型是如何聲明的耍群。 這個(gè)庫(kù)的源代碼其實(shí)就一個(gè)文件义桂,那就是 https://github.com/psf/requests-html/blob/master/requests_html.py找筝,我們看一下它里面的一些 typing 的定義和方法定義。 首先 Typing 的定義部分如下:

from typing import Set, Union, List, MutableMapping, Optional

_Find = Union[List['Element'], 'Element']
_XPath = Union[List[str], List['Element'], str, 'Element']
_Result = Union[List['Result'], 'Result']
_HTML = Union[str, bytes]
_BaseHTML = str
_UserAgent = str
_DefaultEncoding = str
_URL = str
_RawHTML = bytes
_Encoding = str
_LXML = HtmlElement
_Text = str
_Search = Result
_Containing = Union[str, List[str]]
_Links = Set[str]
_Attrs = MutableMapping
_Next = Union['HTML', List[str]]
_NextSymbol = List[str]

這里可以看到主要用到的類型有 Set慷吊、Union袖裕、ListMutableMapping溉瓶、Optional急鳄,這些在上文都已經(jīng)做了解釋,另外這里使用了多次 Union 來(lái)聲明了一些新的類型堰酿,如 _Find 則要么是是 Element 對(duì)象的列表疾宏,要么是單個(gè) Element 對(duì)象,_Result 則要么是 Result 對(duì)象的列表触创,要么是單個(gè) Result 對(duì)象坎藐。另外 _Attrs 其實(shí)就是字典類型,這里用 MutableMapping 來(lái)表示了嗅榕,沒有用 Dict,也沒有用 Mapping吵聪。
接下來(lái)再看一個(gè) Element 類的聲明:

class Element(BaseParser):
 """An element of HTML.
 :param element: The element from which to base the parsing upon.
 :param url: The URL from which the HTML originated, used for ``absolute_links``.
 :param default_encoding: Which encoding to default to.
 """

 __slots__ = [
 'element', 'url', 'skip_anchors', 'default_encoding', '_encoding',
 '_html', '_lxml', '_pq', '_attrs', 'session'
 ]

 def __init__(self, *, element, url: _URL, default_encoding: _DefaultEncoding = None) -> None:
 super(Element, self).__init__(element=element, url=url, default_encoding=default_encoding)
 self.element = element
 self.tag = element.tag
 self.lineno = element.sourceline
 self._attrs = None

 def __repr__(self) -> str:
 attrs = ['{}={}'.format(attr, repr(self.attrs[attr])) for attr in self.attrs]
 return "<Element {} {}>".format(repr(self.element.tag), ' '.join(attrs))

 @property
 def attrs(self) -> _Attrs:
 """Returns a dictionary of the attributes of the :class:`Element <Element>`
 (`learn more <https://www.w3schools.com/tags/ref_attributes.asp>`_).
 """
 if self._attrs is None:
 self._attrs = {k: v for k, v in self.element.items()}

 # Split class and rel up, as there are ussually many of them:
 for attr in ['class', 'rel']:
 if attr in self._attrs:
 self._attrs[attr] = tuple(self._attrs[attr].split())

 return self._attrs

這里 __init__ 方法接收非常多的參數(shù)凌那,同時(shí)使用 _URL_DefaultEncoding 進(jìn)行了參數(shù)類型注解吟逝,另外 attrs 方法使用了 _Attrs 進(jìn)行了返回結(jié)果類型注解帽蝶。 整體看下來(lái),每個(gè)參數(shù)的類型块攒、返回值都進(jìn)行了清晰地注解励稳,代碼可讀性大大提高。 以上便是類型注解和 typing 模塊的詳細(xì)介紹囱井。

搬運(yùn)工

Python 中 typing 模塊和類型注解的使用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驹尼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子庞呕,更是在濱河造成了極大的恐慌新翎,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件住练,死亡現(xiàn)場(chǎng)離奇詭異地啰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)讲逛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門亏吝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人盏混,你說(shuō)我怎么就攤上這事蔚鸥∠郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵株茶,是天一觀的道長(zhǎng)来涨。 經(jīng)常有香客問我,道長(zhǎng)启盛,這世上最難降的妖魔是什么蹦掐? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮僵闯,結(jié)果婚禮上卧抗,老公的妹妹穿的比我還像新娘。我一直安慰自己鳖粟,他們只是感情好社裆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著向图,像睡著了一般泳秀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榄攀,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天嗜傅,我揣著相機(jī)與錄音,去河邊找鬼檩赢。 笑死吕嘀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贞瞒。 我是一名探鬼主播偶房,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼军浆!你這毒婦竟也來(lái)了棕洋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤乒融,失蹤者是張志新(化名)和其女友劉穎拍冠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體簇抵,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庆杜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了碟摆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晃财。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出断盛,到底是詐尸還是另有隱情罗洗,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布钢猛,位于F島的核電站伙菜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏命迈。R本人自食惡果不足惜贩绕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望壶愤。 院中可真熱鬧淑倾,春花似錦、人聲如沸征椒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)勃救。三九已至碍讨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒙秒,已是汗流浹背勃黍。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留税肪,地道東北人溉躲。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓榜田,卻偏偏與公主長(zhǎng)得像益兄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子箭券,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容