It's been suggested before that mypy makes no distinction between a function that doesn't return anything and a function that returns None explicitly, and simply assumes no return value. I think I understand mypy's approach on this since in practice there's no difference between return, return None, and no return statement at all. I also think it's not fair considering a NoReturn is also available, though I suspect it's because Python's history is longer than that of NoReturn.
But consider a hypothetical example when a developer needs to return None:
@dataclass
class IntBox:
value: int
def val(self) -> int:
return self.value
class EmptyBox:
def val(self) -> None:
return None
assert IntBox(1).val() == 1
assert EmptyBox().val() is None
As expected, mypy points out an error: "val" of "EmptyBox" does not return a value [func-returns-value]
In my case such assertions were part of the tests, though I see no harm in wanting to call val anywhere without caring about the return value. E.g. I just want to store the result in a nullable field in a database table.
Considering mypy's current behavior, my solution now is to instruct it to ignore that specific line:
assert EmptyBox().val() is None # type: ignore
Another option would be to use a sentinel value, but that feels like it's getting out of hand.
My understanding is mypy takes a conservative approach here, so what if there was an alternate mechanism to telling it the developer actually wanted to return a None? For example, what if it considered Literal[None] as a type hint distinct from None? I.e:
class EmptyBox:
def val(self) -> Literal[None]:
return None
This would allow mypy (and similar tools - I presume) to keep working as they were, while still allowing an explicit None return value. It looks, at least on the outside, that similar behavior exists for the boolean values:
def the_truth() -> True:
...
is not allowed i.e. error: Invalid type: try using Literal[True] instead? [valid-type], but a literal True is:
def the_truth() -> Literal[True]:
...
While writing this, I'm learning there exists a Never as well. I think Never is interesting, but would not be suitable in my example as I do intend to call val() on an empty box at some point, whereas Never doesn't like return statements.
It's been suggested before that mypy makes no distinction between a function that doesn't return anything and a function that returns
Noneexplicitly, and simply assumes no return value. I think I understand mypy's approach on this since in practice there's no difference betweenreturn,return None, and no return statement at all. I also think it's not fair considering aNoReturnis also available, though I suspect it's because Python's history is longer than that ofNoReturn.But consider a hypothetical example when a developer needs to return
None:As expected, mypy points out an
error: "val" of "EmptyBox" does not return a value [func-returns-value]In my case such assertions were part of the tests, though I see no harm in wanting to call
valanywhere without caring about the return value. E.g. I just want to store the result in a nullable field in a database table.Considering mypy's current behavior, my solution now is to instruct it to ignore that specific line:
Another option would be to use a sentinel value, but that feels like it's getting out of hand.
My understanding is mypy takes a conservative approach here, so what if there was an alternate mechanism to telling it the developer actually wanted to return a
None? For example, what if it consideredLiteral[None]as a type hint distinct fromNone? I.e:This would allow mypy (and similar tools - I presume) to keep working as they were, while still allowing an explicit
Nonereturn value. It looks, at least on the outside, that similar behavior exists for the boolean values:is not allowed i.e.
error: Invalid type: try using Literal[True] instead? [valid-type], but a literalTrueis:While writing this, I'm learning there exists a
Neveras well. I thinkNeveris interesting, but would not be suitable in my example as I do intend to callval()on an empty box at some point, whereasNeverdoesn't likereturnstatements.