无法猜测为什么重载函数实现不接受所有可能的参数
Cannot guess why Overloaded function implementation does not accept all possible arguments
我想完整地输入我的 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.")
# ...
当我 运行 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
的所有可能参数
问题来了。假设有人尝试 运行 PageObject(Driver())
—— 也就是说,我们传入一个 Driver
对象作为第一个参数。
这与您的第一次重载匹配,因此将由 mypy 进行类型检查。但是在运行时实际上发生了什么?第一个 runtime 参数是 by
,所以你的 Driver
对象被分配给 by
,not driver
。所以现在你的类型不匹配,因为 by
应该是 Optional[Tuple[By, str]]
.
类型
可能最简单的解决方法是禁止您的用户完全使用位置参数 mandate that they use only keyword arguments。您可以这样做:
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:
...
现在,mypy 对此进行了类型检查而没有错误,并且执行 PageObject(Driver())
被 mypy 和 Python 都视为错误。相反,您现在需要执行 PageObject(driver=Driver())
.
如果您确实想要允许位置参数,恐怕您需要重新设计代码。也许您可以考虑使用静态方法或类方法等,这样您就可以拥有不同的 "flavors" 构造函数——基本上,就是评论中建议的工厂模式。
可能与某人相关:
这按预期工作,请参阅我的示例:
from typing import Any, Optional, overload, Union
@overload
def a(b: str, c: None) -> int:
...
@overload
def a(b: int, c: int) -> str:
...
def a(b: Any, c: Any) -> Any:
if isinstance(b, str):
return int(b)
if isinstance(b, int):
return str(b * c)
lalala = a('test', None) # ok
lala = a(2, 1) # ok
la = a('test', 'cooltest') # an error
l = a(True, False) # not an error ? I guess mypy treats booleans as ints here
m = a(bytes(123), bytes(123)) # an error
Guido 在此处对 msg379769 的回答
https://bugs.python.org/issue42169
我想完整地输入我的 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.")
# ...
当我 运行 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
的所有可能参数问题来了。假设有人尝试 运行 PageObject(Driver())
—— 也就是说,我们传入一个 Driver
对象作为第一个参数。
这与您的第一次重载匹配,因此将由 mypy 进行类型检查。但是在运行时实际上发生了什么?第一个 runtime 参数是 by
,所以你的 Driver
对象被分配给 by
,not driver
。所以现在你的类型不匹配,因为 by
应该是 Optional[Tuple[By, str]]
.
可能最简单的解决方法是禁止您的用户完全使用位置参数 mandate that they use only keyword arguments。您可以这样做:
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:
...
现在,mypy 对此进行了类型检查而没有错误,并且执行 PageObject(Driver())
被 mypy 和 Python 都视为错误。相反,您现在需要执行 PageObject(driver=Driver())
.
如果您确实想要允许位置参数,恐怕您需要重新设计代码。也许您可以考虑使用静态方法或类方法等,这样您就可以拥有不同的 "flavors" 构造函数——基本上,就是评论中建议的工厂模式。
可能与某人相关:
这按预期工作,请参阅我的示例:
from typing import Any, Optional, overload, Union
@overload
def a(b: str, c: None) -> int:
...
@overload
def a(b: int, c: int) -> str:
...
def a(b: Any, c: Any) -> Any:
if isinstance(b, str):
return int(b)
if isinstance(b, int):
return str(b * c)
lalala = a('test', None) # ok
lala = a(2, 1) # ok
la = a('test', 'cooltest') # an error
l = a(True, False) # not an error ? I guess mypy treats booleans as ints here
m = a(bytes(123), bytes(123)) # an error
Guido 在此处对 msg379769 的回答 https://bugs.python.org/issue42169