为 base class for subclasses 中定义的接口使用不同的固定类型

Use a different fixed type for interfaces defined in the base class for subclasses

我有一个 BaseList 容器,可以将 BaseItem 作为物品。然后我派生了一个新列表 CustomList,我希望它包含 CustomItem

如何在 BaseList 中键入方法以接受 BaseItem 的许多方法。并告诉它使用 CustomItem 派生列表 CustomList?

这是我目前的代码:


from __future__ import annotations
from typing import List, Union, Iterator, overload


class BaseItem:
    pass


class BaseList:
    def __init__(self) -> None:
        self.items: List[BaseItem] = []

    def add_item(self, item: BaseItem) -> None:
        self.items.append(item)

    def __iter__(self) -> Iterator[BaseItem]:
        return iter(self.items)


class CustomItem(BaseItem):
    def __init__(self, value: int) -> None:
        self.value: int = value


class CustomList(BaseList):
    def sum(self) -> int:
        # mypy error: "BaseItem" has no attribute "value"
        return sum(item.value for item in self)

# no error, but it should say: incompatible type; expected "CustomItem".
CustomList().add_item(BaseItem())

container = CustomList()
container.add_item(CustomItem(10))
for item in container:
    # mypy error: `"BaseItem" has no attribute "value"`
    print(item.value)

问题

如何定义类型 A 并在 BaseList 中说它应该解析为 BaseItem 而在 CustomList 中它应该解析为 CustomItem

到目前为止已经试过了

我尝试将 TypeVar 与 bounds 属性一起使用,但似乎没有成功。

约束

我有不止一个子class所以我不想用不同的类型重新实现所有这些方法。此外,还有更多此类方法存在类似问题,例如 __contains____getitem__、class 特定项目等

类型提示也应由 PyCharm 解决,因为目标是在那里获得正确的代码。

制作 BaseList class 通用:

class BaseItem:
    pass


T = TypeVar('T', bound=BaseItem)


class BaseList(Generic[T]):

    def __init__(self) -> None:
        self.items: List[T] = []

    def add_item(self, item: T) -> None:
        self.items.append(item)

    def __iter__(self) -> Iterator[T]:
        return iter(self.items)


class CustomItem(BaseItem):

    def __init__(self, value: int) -> None:
        self.value: int = value


class CustomList(BaseList[CustomItem]):

    def sum(self) -> int:
        reveal_type(self.items)  # Mypy: Revealed type is "builtins.list[CustomItem*]"
        return sum(item.value for item in self)