why mypy-202301071445
Summary
- What is mypy
- Python Annotations
- Annotation PEPs
Notes
What is Mypy?
Mypy 是一個 static type checker for Python3 & Python2.7.
嗯, static type checker. 一定會有一些朋友問說為什麼 python 需要 type checker. python 不是 dynamic-typed language 嘛? 要檢查 type 就不要寫 python 了阿
沒關係我們慢慢解釋
PEP — 483 The Theory of Type Hints && PEP 484 — Type Hints
PEP483, PEP484 是由 Guido van Rossum, Jukka Lehtosalo, Lukasz Langa 在 2014年提出的. 最後實現在了 python 3.5 上
# 就像這樣可以指定回傳的 type -> str
def func_a(a: str, b: str) -> str:
return a + b值得注意的一個特性是: python 的 type hints 是 Function Annotations, function annotations 是沒有強制力的. 如同字面上的意義它就是 function 的註解.
def foo(a: str) -> str:
"""Foo."""
return 'hello' + a
# {function}.__annotations__ 可以呼叫出 Function Annotations
print(foo.__annotations__)
# {'a': <class 'str'>, 'return': <class 'str'>}
# 可以看到 `return` 內註明了我們回傳的屬性是 `str`透過 Function Annotation, python 解放了一些可能性: 第三方套件可以拿到 function return type.
當然在 PEP484 中也有提到
It should also be emphasized that Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention.
對這樣很好, 創造了很多的可能性, 但我們希望保持簡單.
對這樣很好, python 永遠都是 dynamic-typed language
更多 PEP
PEP 526 — Syntax for Variable Annotations
Python Variable Annotations
init_var: int
my_var: int = 5
other_var: int
other_var = 5
print(__annotations__)
# {'init_var': <class 'int'>, 'my_var': <class 'int'>, 'other_var': <class 'int'>}PEP 544 — Protocols: Structural subtyping (static duck typing)
Python Structural subtyping
簡單理解的話, 就是 golang 的 interface.
from typing import Iterator, Iterable
class Bucket:
...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[int]: ...
def collect(items: Iterable[int]) -> int: ...
result: int = collect(Bucket()) # Passes type check
# Bucker 因為實作了 Iterator 的 __len__ & __iter__ . 就可以當 Iterator 使用PEP 586 — Literal Types
在 python3.8 新增的特性: Literal
from typing import Literal
def accepts_only_four(x: Literal[4]) -> None:
pass
accepts_only_four(4) # OK
accepts_only_four(19) # RejectedPEP 589 — TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys
新增 TypedDict
from typing import TypedDict
class Movie(TypedDict):
name: str
year: int
movie: Movie = {
'name': 'Blade Runner',
'year': 1982,
}PEP 591 — Adding a final qualifier to typing
新增了 @final && Final
@final 是 decorator
Final 是 annotation
from typing import final
@final
class Base:
...
class Derived(Base): # Error: Cannot inherit from final class "Base"
...from typing import final
class Base:
@final
def foo(self) -> None:
...
class Derived(Base):
def foo(self) -> None: # Error: Cannot override final attribute "foo"
# (previously declared in base class "Base")
...# With an explicit type
ID: Final[float] = 1
# With no type annotation.
ID: Final = 1所以為什麼需要 Mypy?
所以一切源於 PEP484, 後續的 PEP 是補充概念以及語法. 一般來說 Mypy 可以被運用在兩個地方
- Editor check
- Testing
我沒有辦法明確的跟你說 Mypy 是必要的且適合每個人. 比起寫一般的 python 會需要打更多字, 遵守更多規範. 但遵循這樣的規範寫程式會有幾個好處:
- 易讀的程式碼
- 易於重構的程式碼
- 提升程式碼質量
Python type hints 是屬於 annotations. 它不是強制性的規範. 但大量使用可以有效提昇程式碼的 質量.
在日常開發以及正式的專案導入這樣的工具. 你的同事以及未來的你會更加感謝現在的你的.