python-如何对具有可选参数的装饰器进行类型注释?

前端之家收集整理的这篇文章主要介绍了python-如何对具有可选参数的装饰器进行类型注释? 前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这是我要正确键入注释的确切函数

  1. F = TypeVar('F',bound=Callable[...,Any])
  2. def throtle(_func: Optional[F] = None,*,rate: float = 1) -> Union[F,Callable[[F],F]]:
  3. """Throtles a function call,so that at minimum it can be called every `rate` seconds.
  4. Usage::
  5. # this will enforce the default minimum time of 1 second between function calls
  6. @throtle
  7. def ...
  8. or::
  9. # this will enforce a custom minimum time of 2.5 seconds between function calls
  10. @throtle(rate=2.5)
  11. def ...
  12. This will raise an error,because `rate=` needs to be specified::
  13. @throtle(5)
  14. def ...
  15. """
  16. def decorator(func: F) -> F:
  17. @functools.wraps(func)
  18. def wrapper(*args: Any,**kwargs: Any) -> Any:
  19. time.sleep(rate)
  20. return func(*args,**kwargs)
  21. return cast(F,wrapper)
  22. if _func is None:
  23. return decorator
  24. else:
  25. return decorator(_func)

尽管通过mypy进行插入时没有出现任何错误,但我不确信自己做对了,也不确定如何证明这一点.

最佳答案
您的代码会进行类型检查,但可能不会执行您想要的操作,因为您将返回一个Union.

要检查mypy推断某个变量的类型,可以使用reveal_type.

  1. # Note: I am assuming you meant "throttle" and so I changed your spelling
  2. def throttle1(
  3. _func: Optional[F] = None,rate: float = 1.0
  4. ) -> Union[F,F]]:
  5. # code omitted
  6. @throttle1
  7. def hello1() -> int:
  8. return 42
  9. reveal_type(hello1) # Revealed type is 'Union[def () -> builtins.int,def (def () -> builtins.int) -> def () -> builtins.int]'

假设我们希望hello1是一个返回int的函数(即def()-> builtins.int),我们需要尝试其他方法.

简单策略

最简单的事情是始终要求节流阀的用户“呼叫装饰器”,即使她/他没有重写任何参数也是如此:

  1. def throttle2(*,rate: float = 1.0) -> Callable[[F],F]:
  2. def decorator(func: F) -> F:
  3. @functools.wraps(func)
  4. def wrapper(*args: Any,wrapper)
  5. return decorator
  6. @throttle2() # Note that I am calling throttle2 without arguments
  7. def hello2() -> int:
  8. return 42
  9. reveal_type(hello2) # Revealed type is 'def () -> builtins.int'
  10. @throttle2(rate=2.0)
  11. def hello3() -> int:
  12. return 42
  13. reveal_type(hello3) # Revealed type is 'def () -> builtins.int'

这已经有效并且非常简单.

使用type.overload

如果先前的解决方案不可接受,则可以使用重载.

  1. # Matches when we are overriding some arguments
  2. @overload
  3. def throttle3(_func: None = None,F]:
  4. ...
  5. # Matches when we are not overriding any argument
  6. @overload
  7. def throttle3(_func: F) -> F:
  8. ...
  9. def throttle3(
  10. _func: Optional[F] = None,F]]:
  11. # your original code goes here
  12. @throttle3 # Note: we do not need to call the decorator
  13. def hello4() -> int:
  14. return 42
  15. reveal_type(hello4) # Revealed type is 'def () -> builtins.int'
  16. @throttle3(rate=2.0)
  17. def hello5() -> int:
  18. return 42
  19. reveal_type(hello5) # Revealed type is 'def () -> builtins.int'

您可以通过阅读its official documentationmypy’s documentation on Function overloading了解更多有关如何使用重载的信息.

猜你在找的Python相关文章