我想完全键入我的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的所有可能参数
答案 0 :(得分:0)
这是问题所在。假设有人尝试运行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进行类型检查而没有错误,并且mypy和Python都将执行PageObject(Driver())
视为错误。相反,您现在需要执行PageObject(driver=Driver())
。
如果您要做要允许使用位置参数,恐怕您需要重新设计代码。也许您可以考虑使用静态方法或类方法,以便可以拥有不同的构造函数“味道”,基本上就是注释中建议的工厂模式。
答案 1 :(得分:0)
可能与某人相关:
这按预期工作,请参阅我的示例:
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