具有不同参数的重载构造函数的继承类会出现键入错误

问题描述 投票:0回答:1

使用以下代码:

import abc

class ABCParent(metaclass=abc.ABCMeta):
    def __init__(self, a: str, sibling_type: type[ABCParent]) -> None:
        self.a = a
        self._sibling_type = sibling_type
    def new_sibling(self, a: str) -> ABCParent:
        return self._sibling_type(a)

class ChildA(ABCParent):
    def __init__(self, a: str) -> None:
        super().__init__(a, ChildB)

class ChildB(ABCParent):
    def __init__(self, a: str) -> None:
        super().__init__(a, ChildA)

在严格模式下使用 mypy 时出现以下键入错误。

src/demo_problem.py: note: In member "new_sibling" of class "ABCParent":
src/demo_problem.py:10:16:10:36: error: Missing positional argument "sibling_type" in call to "ABCParent"  [call-arg]
            return self._sibling_type(a)

这是完全合乎逻辑的,因为

ABCParent
请求
sibling_type
参数。但就我而言,
self._sibling_type
将是子类之一,它会重写构造函数,这样就不需要
sibling_type
了。

我能够通过使用子类的

typing.Union
来解决这个问题:

import abc
import typing

TConcreteChild: typing.TypeAlias = typing.Union["ChildA", "ChildB"]

class ABCParent(metaclass=abc.ABCMeta):
    def __init__(self, a: str, sibling_type: type[TConcreteChild]) -> None:
        ...

但我不喜欢这个,因为:

  • 它涉及定义类型别名(
    TConcreteChild
    ),否则毫无用处
  • 如果定义了更多子类,则必须更新此别名的定义
  • 它涉及在类定义之前定义类型,因此需要使用字符串进行前向引用(因此它不能使用新的
    ChildA | ChildB
    语法)。

我怎样才能更干净地做到这一点,同时仍然进行严格的类型检查?

python python-typing mypy
1个回答
0
投票

因此,我认为一种可能有效(并不总是)的方法是,不要将

._sibling_type
设为类型,而是使用泛型类将其设为泛型可调用,

import abc
import typing

P = typing.TypeVar("P", bound="ABCParent")

class ABCParent(typing.Generic[P], metaclass=abc.ABCMeta):
    def __init__(self, a: str, sibling_type: typing.Callable[[str], P]) -> None:
        self.a = a
        self._sibling_type = sibling_type
    def new_sibling(self, a: str) -> P:
        return self._sibling_type(a)

class ChildA(ABCParent["ChildB"]):
    def __init__(self, a: str) -> None:
        super().__init__(a, ChildB)

class ChildB(ABCParent["ChildA"]):
    def __init__(self, a: str) -> None:
        super().__init__(a, ChildA)

类型是可调用的。根据我对

mypy
的经验,这样对待它们效果更好。

© www.soinside.com 2019 - 2024. All rights reserved.