无法猜测为什么重载函数实现不接受所有可能的参数

tet*_*nne 8 python mypy

我想完整输入我的 Python 项目。但我坚持使用可以使用不同参数调用的构造函数。

我试图从最终的构造函数中删除类型,我试图删除一些构造函数......但仍然遇到同样的问题。

class PageObject(ABC):
    logger = logging.getLogger(__name__)

    @overload
    def __init__(self, driver: Driver) -> None:
        ...

    @overload
    def __init__(self, by: Tuple[By, str], driver: Driver) -> None:
        ...

    @overload
    def __init__(self, context: WebElement, driver: Driver) -> None:
        ...

    @overload
    def __init__(self, by: Tuple[By, str], parent: "PageObject") -> None:
        ...

    @overload
    def __init__(self, parent: "PageObject") -> None:
        ...

    def __init__(
        self,
        by: Optional[Tuple[By, str]] = None,
        context: Optional[WebElement] = None,
        parent: Optional["PageObject"] = None,
        driver: Optional[Driver] = None,
    ) -> None:

        if by and context:
            raise ValueError("You cannot provide a locator AND a context.")
        # ...
Run Code Online (Sandbox Code Playgroud)

当我运行 mypy 时,出现以下错误:

base/page_object.py:36: 错误:重载函数实现不接受签名 1 的所有可能参数

base/page_object.py:36: 错误:重载函数实现不接受签名 2 的所有可能参数

base/page_object.py:36: 错误:重载函数实现不接受签名 3 的所有可能参数

base/page_object.py:36: 错误:重载函数实现不接受签名 4 的所有可能参数

base/page_object.py:36: 错误:重载函数实现不接受签名 5 的所有可能参数

Mic*_*x2a 13

问题就在这里。假设有人尝试运行PageObject(Driver())——也就是说,我们传入一个Driver对象作为第一个参数。

这与您的第一个重载相匹配,因此将由 mypy 进行类型检查。但运行时实际发生了什么?第一个运行时参数是by,因此您的Driver对象被分配给by而不是 driver。所以现在你的类型之间不匹配,因为by应该是 type Optional[Tuple[By, str]]

也许最简单的解决方法是完全禁止用户使用位置参数并强制他们仅使用关键字参数。你可以这样做:

class PageObject:
    @overload
    def __init__(self, *, driver: Driver) -> None:
        ...

    @overload
    def __init__(self, *, by: Tuple[By, str], driver: Driver) -> None:
        ...

    @overload
    def __init__(self, *, context: WebElement, driver: Driver) -> None:
        ...

    @overload
    def __init__(self, *, by: Tuple[By, str], parent: "PageObject") -> None:
        ...

    @overload
    def __init__(self, *, parent: "PageObject") -> None:
        ...

    def __init__(
        self,
        *,
        by: Optional[Tuple[By, str]] = None,
        context: Optional[WebElement] = None,
        parent: Optional["PageObject"] = None,
        driver: Optional[Driver] = None,
    ) -> None:
        ...
Run Code Online (Sandbox Code Playgroud)

现在,mypy 对此进行类型检查而不会出现错误,并且PageObject(Driver())mypy 和 Python 都会将其视为错误。相反,您现在需要执行PageObject(driver=Driver()).

如果您确实想允许位置参数,恐怕您需要重新设计代码。也许您可以考虑使用静态方法或类方法等,这样您就可以拥有不同“风格”的构造函数——基本上是注释中建议的工厂模式。