Seb*_*ner 5 python generics mypy
这类似于装饰器更改返回类型时的键入函数,但这次使用通用返回类型:
from typing import Generic, TypeVar, Generic, Callable, Any, cast
T = TypeVar('T')
class Container(Generic[T]):
def __init__(self, item: T):
self.item: T = item
def my_decorator(f: Callable[..., T]) -> Callable[..., Container[T]]:
def wrapper(*args: Any, **kwargs: Any) -> Container[T]:
return Container(f(*args, **kwargs))
return cast(Callable[..., Container[T]], wrapper)
@my_decorator
def my_func(i: int, s: str) -> bool: ...
reveal_type(my_func) # Revealed type is 'def (*Any, **Any) -> file.Container[builtins.bool*]
Run Code Online (Sandbox Code Playgroud)
需要哪种 mypy 魔法来保持参数类型完整my_func?
使用typing.Protocol看起来很有希望,但我不知道如何让它发挥作用。
使用Callable[..., T]是目前对此进行注释的最佳方式。
PEP 612 引入了ParamSpec,它的使用方式与 a 类似TypeVar,可以解决您的问题。目前计划用于 Python 3.10,并将支持旧版本使用typing_extensions
在那里你可以写:
T = TypeVar('T')
P = ParamSpec('P')
def my_decorator(f: Callable[P, T]) -> Callable[P, Container[T]]:
def wrapper(*args: Any, **kwargs: Any) -> Container[T]:
return Container(f(*args, **kwargs))
return cast(Callable[P, Container[T]], wrapper)
Run Code Online (Sandbox Code Playgroud)
mypy 对 PEP 612 的支持尚未完成:https ://github.com/python/mypy/issues/8645 。与 pytype(Google 的 python 类型检查器)相同。
Pyright(微软的 Python 类型检查器)和 Pyre(Facebook 的 Python 类型检查器)已经支持 PEP 612
只是对已接受的答案和PEP612的最终状态进行快速更新,当前的形式如下:
def my_decorator(f: Callable[P, R]) -> Callable[P, Container[R]]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> Container[R]:
return Container(f(*args, **kwargs))
return wrapper
Run Code Online (Sandbox Code Playgroud)
似乎在装饰函数中同时使用显式P.args和类型是强制性的。P.kwargs完整的代码示例是:
from typing import (
Callable,
Generic,
ParamSpec,
TypeVar,
)
T = TypeVar("T")
class Container(Generic[T]):
def __init__(self, item: T):
self.item: T = item
P = ParamSpec("P")
R = TypeVar("R")
def my_decorator(f: Callable[P, R]) -> Callable[P, Container[R]]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> Container[R]:
return Container(f(*args, **kwargs))
return wrapper
@my_decorator
def my_func(i: int, s: str) -> bool:
...
Run Code Online (Sandbox Code Playgroud)
这给出了预期的输入my_func:
(function) def my_func(
i: int,
s: str
) -> Container[bool]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1901 次 |
| 最近记录: |