发布于2025-01-02 16:54 阅读(495) 评论(0) 点赞(11) 收藏(0)
I am trying to add type annotations to a "service container" with relatively strict typing, but am struggling to define the type hints correctly.
Basically, the services container is a glorified dictionary, where the key should be an ABC type, or a Protocol (i.e. the "abstract class"). The dictionary value is a generic ServiceEntry[T]
where T is a subclass of the key ("abstract class").
I've included simplified implementation below, but the full code can be found in this gist: https://gist.github.com/NixonInnes/6b7cf851cd2715aafbf32c4fb54405ac
This is my service entry implementation:
class ServiceLife(Enum):
SINGLETON = 1
TRANSIENT = 2
class ServiceEntry[T]:
service_class: type[T]
service_life: ServiceLife
instance: T | None
def __init__(self, service_class: type[T], service_life: ServiceLife):
self.service_class = service_class
self.service_life = service_life
self.instance = None
self.lock = threading.Lock()
And this is a simplified implementation of the service container:
class ServiceContainer(IServiceContainer):
def __init__(self):
...
self.__services: dict[type[Any], ServiceEntry[Any]] = {}
def _set_service[T](self, key: type[T], value: ServiceEntry[T]) -> None:
with self.__lock:
self.__services[key] = value
def _get_service[T](self, key: type[T]) -> ServiceEntry[T]:
with self.__lock:
return self.__services[key]
@override
def register[T](
self,
abstract_class: type[T],
service_class: type[T],
service_life: ServiceLife = ServiceLife.TRANSIENT,
):
assert issubclass(
service_class, abstract_class
), f"'{service_class.__name__}' does not implement '{abstract_class.__name__}'"
service = ServiceEntry[T](service_class, service_life)
self._set_service(abstract_class, service)
@override
def get[T](self, abstract_class: type[T], **overrides: Any) -> T:
try:
service = self._get_service(abstract_class)
...
with service.lock:
...
instance = self._create_instance(service, overrides)
...
return instance
def _create_instance[T](self, service_entry: ServiceEntry[T], overrides: dict[str, Any]) -> T:
signature = inspect.signature(service_entry.service_class.__init__)
type_hints = get_type_hints(service_entry.service_class.__init__)
kwargs = {}
for name, param in signature.parameters.items():
...
return service_entry.service_class(**kwargs)
I would like to be able to satisfy type checkers so that when I do something like the below, it is able to infer the output service type and ideally detect an invalid registration (i.e. the service_class
is not a subclass of the abstract_class
)
class IFoo(ABC):
...
class Foo(IFoo):
pass
@runtime_checkable
class IBar(Prototype):
...
class Bar(IBar):
pass
services = ServiceContainer()
services.register(IFoo, Foo)
services.register(IBar, Bar)
foo_service = services.get(IFoo)
bar_service = services.get(IBar)
Maybe im being too ambitious with the static typing system?
作者:黑洞官方问答小能手
链接:https://www.pythonheidong.com/blog/article/2046696/77791330e2c5061a685b/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!