Lau*_*che -3 python python-3.x mypy
def timer(func: Callable[..., Any]) -> Callable[..., Any]:
"""Calculates the runtime of a function, and outputs it to logging.DEBUG."""
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
value = func(*args, **kwargs)
end = perf_counter()
_logger = logging.getLogger(__name__ + '.' + func.__name__)
_logger.debug(' runtime: {:.4f} seconds'.format(end - start))
return value
return wrapper
Run Code Online (Sandbox Code Playgroud)
从 Python 3.10 开始,您可以使用以下方法通过装饰器轻松保留所有类型信息ParamSpec:
from collections.abc import Callable
from functools import wraps
from typing import TypeVar, ParamSpec
T = TypeVar('T')
P = ParamSpec('P')
def timer(func: Callable[P, T]) -> Callable[P, T]:
"""Calculates the runtime of a function, and outputs it to logging.DEBUG."""
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
start = perf_counter()
value = func(*args, **kwargs)
end = perf_counter()
_logger = logging.getLogger(__name__ + "." + func.__name__)
_logger.debug(" runtime: {:.4f} seconds".format(end - start))
return value
return wrapper
Run Code Online (Sandbox Code Playgroud)
(对于 python < 3.10,但更喜欢 juanpa.arrivilillaga 的答案来保留有关输入类型的信息)
这里的缩进似乎有点不对劲,但除此之外,是的,类型并没有不正确。不过,你可以让它更精确一点。您输出的函数与作为输入的函数具有相同的返回类型,但您没有注意到这一点。
特别是,你可以这样说
from collections.abc import Callable
from functools import wraps
from typing import TypeVar, ParamSpec
T = TypeVar('T')
P = ParamSpec('P')
def timer(func: Callable[P, T]) -> Callable[P, T]:
"""Calculates the runtime of a function, and outputs it to logging.DEBUG."""
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
start = perf_counter()
value = func(*args, **kwargs)
end = perf_counter()
_logger = logging.getLogger(__name__ + "." + func.__name__)
_logger.debug(" runtime: {:.4f} seconds".format(end - start))
return value
return wrapper
Run Code Online (Sandbox Code Playgroud)
看起来你应该能够对 args/kwargs 做同样的事情,但我在自己的打字经验中没有遇到过这种情况,所以我不能确切地说出如何做。编辑 -有关输入这些内容的更多信息,请参阅此 GitHub 问题;这似乎不可能(还?)。
我想你也可以说
from typing import Callable, TypeVar
T = TypeVar("T")
def timer(func: Callable[..., T]) -> Callable[..., T]:
Run Code Online (Sandbox Code Playgroud)
但这似乎没那么有用。
这种方法的问题在于,现在MyPy丢失了返回类型,或者简而言之,它退化为Any,因此请考虑:
import logging
from typing import Callable, Any
from time import perf_counter
from functools import wraps
def timer(func: Callable[..., Any]) -> Callable[..., Any]:
"""Calculates the runtime of a function, and outputs it to logging.DEBUG."""
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
value = func(*args, **kwargs)
end = perf_counter()
_logger = logging.getLogger(__name__ + '.' + func.__name__)
_logger.debug(' runtime: {:.4f} seconds'.format(end - start))
return value
return wrapper
@timer
def func(x:int) -> int:
return x
def string_func(s: str):
return s[:]
x = 42 * func(42)
reveal_type(x)
string_func(x)
Run Code Online (Sandbox Code Playgroud)
使用方法:
(py37) Juans-MacBook-Pro:tempdata juan$ mypy --version
mypy 0.641
Run Code Online (Sandbox Code Playgroud)
如果我尝试对此进行类型检查,它会通过!
(py37) Juans-MacBook-Pro:tempdata juan$ mypy typing_decorators.py
typing_decorators.py:29: error: Revealed type is 'Any'
Run Code Online (Sandbox Code Playgroud)
我想找到一种解决方案,其中要保留精确的参数,即使用a TypeVar和cast包装器,这样MyPy可以确切地知道类型(假设原始函数被标注):
import logging
from typing import Callable, Any, TypeVar, cast
from time import perf_counter
from functools import wraps
F = TypeVar('F', bound=Callable[..., Any])
def timer(func: F) -> F:
"""Calculates the runtime of a function, and outputs it to logging.DEBUG."""
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
value = func(*args, **kwargs)
end = perf_counter()
_logger = logging.getLogger(__name__ + '.' + func.__name__)
_logger.debug(' runtime: {:.4f} seconds'.format(end - start))
return value
return cast(F, wrapper)
@timer
def func(x:int) -> int:
return x
def string_func(s: str):
return s[:]
x = 42 * func(42)
reveal_type(x)
string_func(x)
Run Code Online (Sandbox Code Playgroud)
在这种情况下:
(py37) Juans-MacBook-Pro:tempdata juan$ mypy typing_decorators.py
typing_decorators.py:32: error: Revealed type is 'builtins.int'
typing_decorators.py:34: error: Argument 1 to "string_func" has incompatible type "int"; expected "str"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
164 次 |
| 最近记录: |