美文网首页程序员Python编程技术
Python 静态类型检查 mypy 示例

Python 静态类型检查 mypy 示例

作者: 融合xx | 来源:发表于2019-09-28 20:55 被阅读0次

    以下所有例子都参考了最新版本的 Python 文档与 mypy 文档

    必备条件

    安装最新版本的 Python 和 mypy

    要学会按需配置自己的编辑器,比如我的 VSCode 就装好了 Python 和 Pyright 扩展

    变量

    age: int = 1
    
    child: bool
    if age < 18:
        child = True
    else:
        child = False
    

    常量

    from typing import Final
    
    RATE: Final = 3000
    
    class Base:
        DEFAULT_ID: Final = 0
    
    RATE = 300  # Error: can't assign to final attribute
    Base.DEFAULT_ID = 1  # Error: can't override a final attribute
    

    内置类型

    from typing import List, Set, Dict, Tuple, Optional
    
    x: int = 1
    x: float = 1.0
    x: bool = True
    x: str = "test"
    x: bytes = b"test"
    
    # 集合类型是首字母大写的
    # 元素的类型写在中括号里面(泛型)
    x: List[int] = [1]
    x: Set[int] = {6, 7}
    
    # 字典需要写出 key 和 value 的类型
    x: Dict[str, float] = {"field": 2.0}
    
    # 元组需要写出所有元素的类型
    x: Tuple[int, str, float] = (3, "yes", 7.5)
    
    # 用 Optional[] 表示可以为 None 的类型
    x: Optional[str] = some_function()
    # mypy 可以推断出 if 语句里 x 不能为 None
    if x is not None:
        print(x.upper())
    # 如果 x 的值不可能为 None, 用 assert
    assert x is not None
    print(x.upper())
    

    函数

    from typing import Callable, Iterator, Union, Optional, List
    
    def stringify(num: int) -> str:
        return str(num)
    
    def plus(num1: int, num2: int) -> int:
        return num1 + num2
    
    def f(num1: int, my_float: float = 3.5) -> float:
        return num1 + my_float
    
    # callable (函数) 类型
    x: Callable[[int, float], float] = f
    
    # 生成器函数会返回可迭代的元素
    def g(n: int) -> Iterator[int]:
        i = 0
        while i < n:
            yield i
            i += 1
    

    from typing import ClassVar
    
    class MyClass:
        attr: int
        # 实例变量可以有默认值
        charge_percent: int = 100
    
        # 什么也不返回,就是返回 None
    
        def __init__(self) -> None:
            ...
    
        # 实例方法,省略 self 的类型
        def my_method(self, num: int, str1: str) -> str:
            return num * str1
    
    # 类可以用作类型
    x: MyClass = MyClass()
    
    # 类变量
    class Car:
        seats: ClassVar[int] = 4
        passengers: ClassVar[List[str]]
    
    # 需要注意还没定义就使用一个类会报错
    def f(foo: A) -> int:  # Error
        ...
    
    class A:
        ...
    
    # 你可以使用字符串的形式来规避
    def f(foo: "A") -> int:  # OK
        ...
    

    Named tuples 命名元组

    from typing import NamedTuple
    
    class Point(NamedTuple):
        x: int
        y: int
    
    p = Point(x=1, y="x")  # Error: Argument has incompatible type "str"; expected "int"
    

    异步迭代器

    from typing import AsyncIterator
    
    async def gen() -> AsyncIterator[bytes]:
        lst = [b async for b in gen()]  # 推断类型是 "List[bytes]"
        yield "no way"  # Error: Incompatible types (got "str", expected "bytes")
    

    类型别名

    AliasType = Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]
    
    def f() -> AliasType:
        ...
    

    Dataclasses 数据类

    from dataclasses import dataclass, field
    
    @dataclass
    class Application:
        name: str
        plugins: List[str] = field(default_factory=list)
    
    test = Application("Testing...")  # OK
    bad = Application("Testing...", "with plugin")  # Error: List[str] expected
    

    泛型

    from typing import TypeVar, Generic
    
    T = TypeVar("T")
    
    class Stack(Generic[T]):    # 泛型
        def __init__(self) -> None:
            self.items: List[T] = []
    
        def push(self, item: T) -> None:
            self.items.append(item)
    
        def pop(self) -> T:
            return self.items.pop()
    
        def empty(self) -> bool:
            return not self.items
    
    # Stack[int] 实例
    stack = Stack[int]()
    stack.push(2)
    stack.pop()
    stack.push("x")        # Type error
    

    Literal types

    PrimaryColors = Literal["red", "blue", "yellow"]
    SecondaryColors = Literal["purple", "green", "orange"]
    AllowedColors = Literal[PrimaryColors, SecondaryColors]
    
    def paint(color: AllowedColors) -> None: ...
    
    paint("red")        # OK
    paint("turquoise")  # Error
    

    Protocol 协议

    实现结构化子类型(静态鸭子类型),可以当成接口一样用。

    from typing import Iterable, Protocol
    
    class SupportsClose(Protocol):
        def close(self) -> None:
           ...  # 函数体可以为空 (explicit '...')
    
    class Resource:  # 没有写 SupportsClose
        def close(self) -> None:
           self.resource.release()
    
    def close_all(items: Iterable[SupportsClose]) -> None:
        for item in items:
            item.close()
    
    close_all([Resource(), open("some/file")])  # OK
    

    Abstractmethod 抽象方法

    方法可以有默认的实现,但是抽象方法规定必须在子类中实现。

    from typing import Protocol
    from abc import abstractmethod
    
    class Example(Protocol):
        def first(self) -> int:
            return 42
    
        @abstractmethod
        def second(self) -> int:  # 没有默认实现
            raise NotImplementedError  # 防止这个方法被调用
    

    Enum 枚举

    如果要像 C 语言一样定义枚举的话,也是用类来实现的。

    from enum import Enum
    
    class Color(Enum):
        RED = 1
        GREEN = 2
        BLUE = 3
    
    print(Color.RED)
    

    这样就能用类当成枚举一样用了。

    参考资料

    相关文章

      网友评论

        本文标题:Python 静态类型检查 mypy 示例

        本文链接:https://www.haomeiwen.com/subject/hmxauctx.html