You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带具体类型的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 17:55:38