考虑以下代码:
from functools import wraps
from netmiko import ConnectHandler
class my_class():
def __init__(self):
self.connection = ConnectHandler()
def validate_connection():
@wraps(func)
def inner(self, *args, **kwargs):
if self.connection is None:
raise Exception(
f"No connection to {self.name}({self.ip}):22\n"
)
return func(self, *args, **kwargs)
return inner
@validate_connection
def send_command(self, *args, **kwargs) -> Union[str, list[Any], dict[str, Any]]:
return self.connection.send_command(*args, **kwargs, read_timeout=60)
输入提示
validate_connection()
方法的正确方法是什么,请解释一下你是如何想到的。
目前 MyPy 在
@validate_connection
行上给出以下错误
Argument 1 to "validate_connection" has incompatible type "Callable[[my_class, VarArg(Any), KwArg(Any)], str | list[Any] | dict[str, Any]]"; expected "my_class"
我会将装饰器拉出到顶级函数中,然后向
self
添加显式类型提示。然后你可以为函数参数创建一个类型变量。此示例中有一个强制转换,并假设它将始终在特定类上使用,但大大简化了类型提示。
from functools import wraps
from typing import Any, TypeVar, Callable, cast, List
Func = TypeVar("Func", bound=Callable[..., Any])
def validate_connection(func: Func) -> Func:
@wraps(func)
def inner(self: "MyClass", *args: Any, **kwargs: Any) -> Any:
if self.connection is None:
raise Exception
return func(self, *args, **kwargs)
return cast(Func, inner)
class MyClass:
def __init__(self) -> None:
self.connection = None
@validate_connection
def send_command(self, foo: int, bar: str) -> List[str]:
return []
mypy 输出证明验证的示例:
MyClass().send_command(1, "2").append("3")
# No error :)
MyClass().send_command(1, "2").append(3)
# error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str" [arg-type]
MyClass().send_command(1, 2).append("3")
# error: Argument 2 to "send_command" of "MyClass" has incompatible type "int"; expected "str" [arg-type]