Reputation: 247
I am using Python type hints and mypy with the following code:
from typing import Optional
def compute(
use_wcog: bool = False,
Xt: Optional[float] = None,
Xd: Optional[float] = None,
Xw: Optional[float] = None,
Xs: Optional[float] = None,
):
if use_wcog:
reqs = (Xt, Xd, Xw)
assert all([_ is not None for _ in reqs])
res = ((Xt**2 + Xw**2) / Xd)**2
else:
reqs = (Xs, Xd)
assert all([_ is not None for _ in reqs])
res = (Xs**2 / Xd)**2
return res
I get the following error: Unsuported operand types for ** (float and None) (mypy error)
What is the proper way of handling it?
Upvotes: 0
Views: 1492
Reputation: 71424
Mypy isn't quite clever enough to narrow the type based on all
and the list comprehension. Make it simple:
if use_wcog:
assert Xt and Xd and Xw
res = ((Xt**2 + Xw**2) / Xd)**2
else:
assert Xs and Xd
res = (Xs**2 / Xd)**2
FWIW, having these dependencies embedded in the body of the function makes typing largely useless IMO -- it's very easy to call this function in a way that will error at runtime, and the whole point of static typing is to make usage errors detectable statically. Given that the two implementations of the function have completely different contracts with respect to what inputs are expected and what result is returned, I'd just make it two functions.
def compute_wcog(Xt: float, Xd: float, Xw: float) -> float:
return ((Xt**2 + Xw**2) / Xd)**2
def compute_no_wcog(Xd: float, Xs: float) -> float:
return (Xs**2 / Xd)**2
If you really need to have a single compute
function with effectively multiple interfaces, you can use the @overload
decorator:
from typing import Literal, Optional, overload
@overload
def compute(use_wcog: Literal[True], Xt: float, Xd: float, Xw: float, Xs: None) -> float: ...
@overload
def compute(use_wcog: Literal[False], Xt: None, Xd: float, Xw: None, Xs: float) -> float: ...
def compute(
use_wcog: bool = False,
Xt: Optional[float] = None,
Xd: Optional[float] = None,
Xw: Optional[float] = None,
Xs: Optional[float] = None,
):
assert Xd is not None
if use_wcog:
assert Xt is not None and Xw is not None
res = ((Xt**2 + Xw**2) / Xd)**2
else:
assert Xs is not None
res = (Xs**2 / Xd)**2
return res
compute(True, 1.0, 1.0, 1.0, None) # works
compute(False, None, 1.0, None, 1.0) # works
compute(True, None, 1.0, None, 1.0) # error: No overload variant of "compute" matches argument types...
but this is obviously a lot more code for not a lot of gain. :)
Upvotes: 3