带具体类型的super().__init__调用类型检查问题及泛型困惑
跨体系类继承的类型检查报错问题
以下是两个类继承体系,各自的基类依赖另一体系的基类。当我派生具体类时,会将对应体系的具体类型作为依赖。代码运行符合预期,但PyCharm的typechecker会报错。我认为从具体类型向下转换为基类是可行的,因为基类仅处理向下转换后的类型,不依赖具体类型的特性。
from typing import reveal_type class BaseView: ... class BaseController: def __init__(self, view: BaseView): self.view = view class ConcreteView(BaseView): attr = "42" class ConcreteController(BaseController): def __init__(self, view: ConcreteView): super().__init__(view) def meth(self): # gives an # Unresolved attribute reference 'attr' for class 'BaseView' # warning print(self.view.attr) # okay print(reveal_type(self.view)) if __name__ == '__main__': concrete_view = ConcreteView() controller = ConcreteController(concrete_view) controller.meth()
一种折衷方案是使用工厂模式来让类型检查器认可,但linter仍无法解析,且我不希望为满足类型检查而引入复杂的工厂模式。
from typing import reveal_type, Callable class BaseView: ... class BaseController: def __init__(self, view_factory: Callable): self.view = view_factory() class ConcreteView(BaseView): attr = "42" def __init__(self): self.b = 10 class ConcreteController(BaseController): def __init__(self, view_factory: Callable[[], ConcreteView]): super().__init__(view_factory) def meth(self): # warning gone but lint still not working print(self.view.attr) print(self.view.b) # okay print(reveal_type(self.view)) if __name__ == '__main__': controller = ConcreteController(lambda: ConcreteView()) controller.meth()
此外,我也尝试使用泛型。
from typing import reveal_type, Generic, TypeVar T = TypeVar("") class BaseView(Generic[T]): ... class BaseController(Generic[T]): def __init__(self, view: T): self.view = view class ConcreteView(BaseView): attr = "42" class ConcreteController(BaseController): def __init__(self, view: BaseView[ConcreteView]): super().__init__(view) def meth(self): # no warning typchecker print(self.view.attr) # but no lint self.view # okay print(reveal_type(self.view)) if __name__ == '__main__': concrete_view = ConcreteView() controller = ConcreteController(concrete_view) controller.meth()
进一步继承
基于mr_mo的回答,为了让子类继承保持泛型特性,我需要为控制器添加泛型。
from typing import Generic, TypeVar T = TypeVar("T") class BaseView: ... class BaseController(Generic[T]): def __init__(self, view: T) -> None: self.view = view class ConcreteView(BaseView): attr = "Concrete View" class MoreConcreteView(ConcreteView): attr = "More concrete view" foo = "another attribute of more concrete view" class ConcreteController(Generic[T], BaseController[T | ConcreteView]): def __init__(self, view: ConcreteView) -> None: super().__init__(view) def meth(self) -> None: print(self.view.attr) print(type(self.view)) class MoreConcreteController(Generic[T], ConcreteController[T | MoreConcreteView]): def __init__(self, view): super().__init__(view) def meth(self): print(self.view.foo) print(self.view.attr) print(type(self.view)) if __name__ == "__main__": concrete_view = ConcreteView() controller = ConcreteController(concrete_view) controller.meth() mcv = MoreConcreteView() mcc = MoreConcreteController(mcv) mcc.meth()
看来我仍未理解Python泛型的概念...
内容的提问来源于stack exchange,提问作者seimen
相关产品推荐
相关产品推荐

