如何定义跨Python版本兼容且要求至少1个参数的Callable自定义类型
跨Python版本兼容实现「至少1个参数」的Callable类型定义方案
最优解决方案:使用Protocol自定义可调用协议
这个方案可以完美匹配「至少1个任意类型参数、后续参数无限制、返回值为int」的语义,同时兼容Python 3.8及更高版本,静态类型检查器可正常识别校验:
# Python 3.8 及以上版本可直接使用typing内置的Protocol from typing import Protocol, Any, runtime_checkable # 若需要兼容Python 3.7及更低版本,替换上面的导入为: # from typing_extensions import Protocol, runtime_checkable # from typing import Any @runtime_checkable class CustomCallable(Protocol): def __call__(self, first_arg: Any, *args: Any, **kwargs: Any) -> int: ...
效果说明
- 类型校验规则完全符合需求:要求可调用对象至少有1个位置参数,后续可接任意数量的位置、关键字参数,返回值为int
- 支持静态类型检查:mypy、pyright等检查工具可正常识别规则
- 支持运行时校验:加了
@runtime_checkable装饰器后,可直接用isinstance(func, CustomCallable)做运行时判断
备选方案:按Python版本分支定义
如果不想额外引入Protocol逻辑,也可以根据Python版本做分支适配,保证各版本都能正常运行:
import sys from typing import Callable, Any if sys.version_info >= (3, 9): # 3.9+直接用原生支持的写法 CustomType = Callable[[Any, ...], int] else: # 3.8及更低版本用Protocol兼容 from typing_extensions import Protocol, runtime_checkable @runtime_checkable class CustomType(Protocol): def __call__(self, first_arg: Any, *args: Any, **kwargs: Any) -> int: ...
注意事项
- 如果不需要运行时类型校验,可以删除
@runtime_checkable装饰器,减少不必要的性能开销 - 若需兼容Python 3.7及更低版本,需提前安装
typing-extensions依赖:pip install typing-extensions - 不推荐使用
type: ignore注释忽略3.8版本的报错,该做法会导致静态类型检查失效,无法正确校验参数数量规则
内容的提问来源于stack exchange,提问作者Twald
相关产品推荐
相关产品推荐

