为服务容器添加严格类型注解的类型提示定义难题
解决方案:用Python泛型与类型约束实现严格服务容器类型检查
你的需求完全在Python静态类型系统(如mypy)的能力范围内,并非要求过高。通过合理使用typing模块的泛型、类型约束特性,就能实现注册时的类型校验与获取时的自动类型推断。以下是具体实现方案:
1. 定义核心类型与ServiceEntry
from abc import ABC, abstractmethod from typing import TypeVar, Generic, Type, Protocol # 绑定到抽象类/Protocol的TypeVar,确保T必须是抽象类型的子类 T = TypeVar('T', bound=ABC | Protocol) class ServiceEntry(Generic[T]): def __init__(self, service_class: Type[T]): self.service_class = service_class self.instance: T | None = None def get_instance(self) -> T: if self.instance is None: self.instance = self.service_class() return self.instance
2. 实现带严格类型注解的ServiceContainer
class ServiceContainer: def __init__(self): # 建立抽象类型到对应ServiceEntry的类型映射 self._services: dict[Type[T], ServiceEntry[T]] = {} def register(self, abstract_type: Type[T], service_class: Type[T]) -> None: """注册服务:静态检查+运行时双重校验service_class是否为抽象类型的子类""" if not issubclass(service_class, abstract_type): raise TypeError(f"{service_class.__name__} 不是 {abstract_type.__name__} 的子类") self._services[abstract_type] = ServiceEntry(service_class) def get(self, abstract_type: Type[T]) -> T: """获取服务实例:类型检查器自动推断返回值为抽象类型的实现类""" entry = self._services.get(abstract_type) if not entry: raise ValueError(f"未注册服务:{abstract_type.__name__}") return entry.get_instance()
3. 测试类型校验与自动推断
定义抽象类型与实现类
class IUserService(ABC): @abstractmethod def get_user(self) -> str: pass class UserService(IUserService): def get_user(self) -> str: return "Alice" # 非法实现:未继承抽象类 class InvalidService: def get_user(self) -> str: return "Bob"
注册与获取的类型验证
container = ServiceContainer() # 合法注册:类型检查器无报错 container.register(IUserService, UserService) # 非法注册:静态检查器会直接提示类型不兼容,运行时也会抛出TypeError # container.register(IUserService, InvalidService) # 静态+运行时双重报错 # 获取服务:类型检查器自动推断返回值为IUserService(实际是UserService实例) user_service = container.get(IUserService) print(user_service.get_user()) # 输出 Alice
扩展支持Protocol类型
如果需要支持基于行为的Protocol抽象,只需按标准方式定义Protocol即可,类型检查器会自动校验实现类是否符合协议:
class ILogger(Protocol): def log(self, message: str) -> None: pass class ConsoleLogger: def log(self, message: str) -> None: print(f"Log: {message}") # 注册Protocol类型,静态检查器自动校验实现是否符合协议 container.register(ILogger, ConsoleLogger) logger = container.get(ILogger) logger.log("Test log") # 类型检查完全通过
内容的提问来源于stack exchange,提问作者NixonInnes
相关产品推荐
相关产品推荐

