jneo8.com

Search

Search IconIcon to open search

why mypy-202301071445

Last updated Jan 7, 2023 Edit Source

# why mypy-202301071445

# Summary

# 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 上

1
2
3
# 就像這樣可以指定回傳的 type -> str
def func_a(a: str, b: str) -> str:
    return a + b

值得注意的一個特性是: python 的 type hints 是 Function Annotations, function annotations 是沒有強制力的. 如同字面上的意義它就是 function 的註解.

1
2
3
4
5
6
7
8
9
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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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

1
2
3
4
5
6
7
from typing import Literal

def accepts_only_four(x: Literal[4]) -> None:
    pass

accepts_only_four(4)   # OK
accepts_only_four(19)  # Rejected

PEP 589 – TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys

新增 TypedDict

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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

1
2
3
4
5
6
7
8
from typing import final

@final
class Base:
    ...

class Derived(Base):  # Error: Cannot inherit from final class "Base"
    ...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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")
        ...
1
2
3
4
5
# With an explicit type
ID: Final[float] = 1

# With no type annotation.
ID: Final = 1

# 所以為什麼需要 Mypy?

所以一切源於 PEP484, 後續的 PEP 是補充概念以及語法. 一般來說 Mypy 可以被運用在兩個地方

  1. Editor check
  2. Testing

我沒有辦法明確的跟你說 Mypy 是必要的且適合每個人. 比起寫一般的 python 會需要打更多字, 遵守更多規範. 但遵循這樣的規範寫程式會有幾個好處:

Python type hints 是屬於 annotations. 它不是強制性的規範. 但大量使用可以有效提昇程式碼的 質量.

在日常開發以及正式的專案導入這樣的工具. 你的同事以及未來的你會更加感謝現在的你的.


# References

PEP 3107 – Function Annotations