使用importlib创建的模块对应的mypy类型是什么?
类型标注方案
通用场景标注
所有Python模块对象的标准类型是types.ModuleType,这是mypy官方认可的模块类型,通用场景下直接使用该类型标注返回值即可,修改后的完整代码如下:
from importlib.machinery import SourceFileLoader from importlib.util import spec_from_loader, module_from_spec from pathlib import Path from typing import Union from types import ModuleType PathStr = Union[Path, str] def load_module(module_path: PathStr, module_name: str = "module") -> ModuleType: """Load and return a module""" # 注意SourceFileLoader要求路径为字符串,此处主动转换避免mypy报错 loader = SourceFileLoader(module_name, str(module_path)) spec = spec_from_loader(loader.name, loader) module = module_from_spec(spec) loader.exec_module(module) return module
进阶:自定义模块结构的精确标注
如果你提前知道待加载模块的成员结构,想要获得更严格的类型检查,可以使用Protocol定义模块的结构契约,用自定义的Protocol作为返回类型,示例如下:
from typing import Protocol, Union from pathlib import Path from importlib.machinery import SourceFileLoader from importlib.util import spec_from_loader, module_from_spec # Python 3.8以下版本需从typing_extensions导入Protocol # from typing_extensions import Protocol PathStr = Union[Path, str] # 定义你预期模块包含的属性和方法 class MyExpectedModule(Protocol): VERSION: str def run_task(self, param: int) -> bool: ... def load_module(module_path: PathStr, module_name: str = "module") -> MyExpectedModule: loader = SourceFileLoader(module_name, str(module_path)) spec = spec_from_loader(loader.name, loader) module = module_from_spec(spec) loader.exec_module(module) return module
使用该方案后,你调用返回模块的属性或方法时,mypy会自动做类型校验。
注意事项
- 动态加载的模块mypy无法静态校验实际结构和你定义的Protocol是否匹配,需要你自行保证加载的模块符合约定结构
- Python 3.8以下版本使用
Protocol需要提前安装依赖:pip install typing-extensions
内容的提问来源于stack exchange,提问作者Jean-Francois T.
相关产品推荐
相关产品推荐

