You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
"""TODO:`foo` expects two keyword arguments - `name` of type `str`, and `age` of type `int`."""fromtypingimportUnpack, TypedDictclassPerson(TypedDict):
name: strage: intdeffoo(**kwargs: Unpack[Person]):
...
## End of your code ##person: Person= {"name": "The Meaning of Life", "age": 1983}
foo(**person)
foo(**{"name": "Brian", "age": 30})
foo(**{"name": "Brian"}) # expect-type-errorperson2: dict[str, object] = {"name": "Brian", "age": 20}
foo(**person2) # expect-type-errorfoo(**{"name": "Brian", "age": "1979"}) # expect-type-error
"""TODO:Class `Foo` has a class variable `bar`, which is an integer."""fromtypingimportClassVarclassFoo:
bar: ClassVar[int]
"""Hint: No need to write __init__"""## End of your code ##Foo.bar=1Foo.bar="1"# expect-type-errorFoo().bar=1# expect-type-error
"""TODO:`return_self` should return an instance of the same type as the current enclosed class."""fromtypingimportSelfclassFoo:
defreturn_self(self) ->Self:
...
# Another solution using TypeVar# from typing import TypeVar## T = TypeVar('T', bound='Foo')## class Foo:# def return_self(self: T) -> T:# ...## End of your code ##classSubclassOfFoo(Foo):
passf: Foo=Foo().return_self()
sf: SubclassOfFoo=SubclassOfFoo().return_self()
sf: SubclassOfFoo=Foo().return_self() # expect-type-error
"""TODO: Define a protocol for class `SupportsQuack` that supports a "quack" method."""fromtypingimportProtocolclassSupportsQuack(Protocol):
defquack(self) ->None:
...
## End of your code ##classDuck:
defquack(self) ->None:
print("quack!")
classDog:
defbark(self) ->None:
print("bark!")
duck: SupportsQuack=Duck()
dog: SupportsQuack=Dog() # expect-type-error
callable-protocol
"""TODO:Define a callable type that accepts a string parameter called `name` and returns None."""fromtypingimportProtocolclassSingleStringInput(Protocol):
def__call__(self, name: str) ->None:
...
## End of your code ##defaccept_single_string_input(func: SingleStringInput) ->None:
func(name="name")
defstring_name(name: str) ->None:
...
defstring_value(value: str) ->None:
...
defreturn_string(name: str) ->str:
returnnameaccept_single_string_input(string_name)
accept_single_string_input(string_value) # expect-type-erroraccept_single_string_input(return_string) # expect-type-error
"""TODO:`gen` is a generator that yields a integer, and can accept a string sent to it.It does not return anything."""fromcollections.abcimportGeneratordefgen() ->Generator[int, str, None]:
"""You don't need to implement it"""
...
## End of your code ##fromtypingimportassert_typegenerator=gen()
assert_type(next(generator), int)
generator.send("sss")
generator.send(3) # expect-type-error
never
Never 和 NoReturn 代表 底类型(Bottom Type),一种没有成员的类型。
它们可被用于指明一个函数绝不会返回,例如 sys.exit():
fromtypingimportNever# 或 NoReturndefnever_call_me(arg: Never) ->None:
passdefint_or_str(arg: int|str) ->None:
never_call_me(arg) # 类型检查器错误matcharg:
caseint():
print("It's an int")
casestr():
print("It's a str")
case _:
never_call_me(arg) # OK, arg is of type Never (or NoReturn)
Never 和 NoReturn 在类型系统中具有相同的含义并且静态类型检查器会以相同的方式对待这两者。
"""TODO:Annotate the function `read_buffer`, which accepts anything that is a buffer.See https://docs.python.org/3.12/reference/datamodel.html#object.__buffer__"""fromcollections.abcimportBufferdefread_buffer(b: Buffer):
...
## End of your code ##fromarrayimportarrayclassMyBuffer:
def__init__(self, data: bytes):
self.data=bytearray(data)
self.view=Nonedef__buffer__(self, flags: int) ->memoryview:
self.view=memoryview(self.data)
returnself.viewread_buffer(b"foo")
read_buffer(memoryview(b"foo"))
read_buffer(array("l", [1, 2, 3, 4, 5]))
read_buffer(MyBuffer(b"foo"))
read_buffer("foo") # expect-type-errorread_buffer(1) # expect-type-errorread_buffer(["foo"]) # expect-type-error
a= [4]
reveal_type(a) # -> error: Revealed type is 'builtins.list[builtins.int*]'
使用 cast 来强制指定类型:
fromtypingimportList, casta= [4]
b=cast(List[int], a) # passes finec=cast(List[str], a) # type: List[str] # passes fine (no runtime check)reveal_type(c) # -> error: Revealed type is 'builtins.list[builtins.str]'
使用类型忽略标记禁用一行中的错误:
x=confusing_function() # type: ignore # see mypy/issues/1167
Python 为什么要需要类型 1
一些有用的资料
Python 类型基础
常见关键字
Union
Union[X, Y]
等价于X | Y
(3.10 及以上),意味着满足X
或Y
之一。参数必须是某种类型(
X
或Y
),且至少有一个。Optional
Optional[X]
等价于X | None
(或Union[X, None]
) 。TypeVar
可以使用
TypeVar
构造定义它自己的通用容器:TypeVar
还可以通过指定多个类型参数来创建泛型,表示参数可以是这些类型之一:Any
可以使用
Any
类型可以在不需要的地方禁用类型检查:类型别名 (TypeAlias)
类型别名是使用
type
语句来定义的,它将创建一个TypeAliasType
的实例。 在这个示例中,Vector 和 list[float] 将被静态类型检查器等同处理:
type
语句是在 Python 3.12 中新增加的。 为了向下兼容,类型别名也可以通过简单的赋值来创建:
也可以用 TypeAlias 标记来显式说明这是一个类型别名:
NewType
NewType
用于创建一个新的类型,它与原始类型具有相同的值,但类型检查器会将其视为不同的类型。
静态类型检查器把新类型当作原始类型的子类,这种方式适用于捕捉逻辑错误:
函数
可调用对象(Callable)
Callable[[int], str]
表示一个接受int
类型的单个形参并返回一个str
的函数。如果不确定参数数量,可以使用
Callable[..., ReturnType]
来表示任意数量的参数Paramspec
ParamSpec 是 Python 3.10 引入的,它允许你在类型提示中使用可变数量和类型的参数。
主要用于以下场景:
Concatenate
主要用于与 Callable 和 ParamSpec(参数规格)配合使用。它允许我们在类型提示中将多
个参数类型拼接在一起,从而创建更灵活的函数类型提示。
unpack
Python 3.11 开始引入了类型参数展开(Type Parameter Unpacking),可以通过 * 操作
符解包类型参数。这允许你在类型提示中处理变长的参数列表和泛型参数。
Unpack 也可以与 typing.TypedDict 一起使用以便在函数签名中对 **kwargs 进行类型标
注
TypeVarTuple
TypeVarTuple 可以定义“变长元组”(variadic tuples)类型。这种类型提示可以捕获多个
类型,并且允许元组长度动态变化。它类似于泛型中的 TypeVar,但 TypeVarTuple 是专门
用于处理可变数量的类型参数的。
TypeVarTuple 用于定义一组任意数量的类型参数,它们可以一起表示一个变长的元组或任
意长的参数列表。
TypeVarTuple 定义一个类型元组,它可以代表任意数量的类型。
Unpack 用于从 TypeVarTuple 中提取类型参数,并应用到函数或类中。
示例
定义一个函数,它接受一个 Tuple,其中的元素可以是任意类型,并返回这个元组。我们可
以使用 TypeVarTuple 来定义这样一个函数:
在这个例子中:
Ts = TypeVarTuple('Ts')
定义了一个类型变量Ts
,它可以代表一组类型。my_tuple_func
函数接受一个 Tuple,这个元组的类型是由Unpack[Ts]
解包的。Tuple[Unpack[Ts]]
表示这个元组可以包含多个类型。示例 2
TypeGuard
TypeGuard
是一种类型提示,用于告诉类型检查器某个函数在运行时能够对变量的类型进行校验和收缩。它通常用于类型推断工具(例如
mypy
)来缩小类型范围。假设我们有一个函数
is_str_list
,它接受一个list
并检查该列表中的所有元素是否都是字符串。我们希望在通过该检查后,类型检查器能够推断出列表是由字符串组成的。
在这个例子中:
is_str_list
是一个自定义类型守卫函数,使用TypeGuard
来标注返回值。返回类型
TypeGuard[List[str]]
告诉类型检查器,如果is_str_list
返回True
,则传入的
values
类型会被认为是List[str]
。因此,当我们在
if
语句中调用is_str_list
后,my_list
的类型会自动缩小到List[str]
,而不再是最初的List[Union[str, int]]
。类
ClassVar
ClassVar
注解是指,给定属性应当用作类变量,而不应设置在类实例上。用法如下:Self
表示当前闭包内的类
此注解在语法上等价于以下代码,但形式更为简洁:
通常来说,如果某些内容返回
self
,如上面的示例所示,您应该使用Self
作为返回值注解。如果
Foo.return_self
被注解为返回"Foo"
,那么类型检查器将推断从SubclassOfFoo.return_self
返回的对象是Foo
类型,而不是SubclassOfFoo
。challenge:
泛型(Generic)
TypeVar
TypeVar
可以用来定义一个类型变量,它可以代表任意类型,并且可以在多个地方重用。泛型函数和类可以通过使用
类型形参语法
来实现参数化:TypeVar
提供bound
参数可以约束它只能是某种类型的子类。泛型函数(Generic Functions)
泛型类
在泛型类中,类的属性和方法可以适应不同的数据类型。通过 Generic 类,我们可以将类
声明为泛型类。
泛型类定义
例如,我们可以定义一个简单的容器类,它能够存储任意类型的数据:
泛型类隐式继承自
Generic
。为了与 Python 3.11 及更低版本兼容,也允许显式地从Generic
继承以表示泛型类:泛型和继承
在面向对象编程中,泛型类可以与继承结合使用,允许子类继承父类的泛型行为。
在这个例子中,
Animal
是一个泛型类,Dog
继承了Animal
,并将泛型T
限定为str
类型。overload
@overload
装饰器可以用来声明同一函数的多个版本,每个版本有不同的参数类型和返回值类型,但在运行时不会实际执行。mypy 会根据参数类型来推断正确的类型签名。
非
@overload
装饰的定义将在运行时使用但应被类型检查器忽略。在运行时,直接调用以@overload
装饰的函数将引发 NotImplementedError。challenge:
Protocol
用于定义“结构化子类型”(structural subtyping),也称为“鸭子类型”。
Protocol
允许我们通过“接口”来定义一个类型,而不强制要求对象必须显式继承这些接口。只要一个对
象实现了所需的方法或属性,它就可以被认为符合某个
Protocol
。callable-protocol
TypedDict
TypedDict 声明一个字典类型,字典定义一个具有特定键和值类型的字典结构,可以像定义
类一样定义字典的键和值的类型,确保字典的键和值符合预期。 可以使用 NotRequired 将
单独的键标记为非必要。
默认情况下,所有的键都必须出现在一个 TypedDict 中。可以使用 NotRequired 将单独
的键标记为非必要
使用 total=False 时,TypedDict 中单独的键可以使用 Required 标记为必要的
其他
Literal
特殊类型注解形式,用于定义“字面值类型”。
Literal 可以用来向类型检查器说明被注解的对象具有与所提供的字面量之一相同的值。
LiteralString
只包括字符串字面值的的特殊类型。
LiteralString 对于会因用户可输入任意字符串而导致问题的敏感 API 很有用。例如,上
述两处导致类型检查器报错的代码可能容易被 SQL 注入攻击。
装饰器(decorator)
描述器(descriptor)
Self
是一个特殊类型,表示当前闭包内的类。此注解在语法上等价于以下代码,但形式更为简洁:
生成器(generator)
生成器可以使用泛型类型
Generator[YieldType, SendType, ReturnType]
来标。 例如:never
Never 和 NoReturn 代表 底类型(Bottom Type),一种没有成员的类型。
它们可被用于指明一个函数绝不会返回,例如 sys.exit():
或者用于定义一个绝不应被调用的函数,因为不存在有效的参数,例如 assert_never():
Never 和 NoReturn 在类型系统中具有相同的含义并且静态类型检查器会以相同的方式对待这两者。
buffer
TODO: 协变,逆变,不变(covariant, contravariant, invariant)
排查工具
使用
reveal_type
查看推断类型使用
cast
来强制指定类型:使用类型忽略标记禁用一行中的错误:
生成 type annotation
mypy stubgen
mypy/mypy/stubgen.py at master · python/mypymonkeytype
Instagram/MonkeyType: A Python library that generates static type annotations by collecting runtime types一些类型检查工具
The text was updated successfully, but these errors were encountered: