常見數(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
袖裕、List
、MutableMapping
溉瓶、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ì)介紹囱井。