How to Specify "Nullable" Return Type with Type Hints

How to specify nullable return type with type hints

You're looking for Optional.

Since your return type can either be datetime (as returned from datetime.utcnow()) or None you should use Optional[datetime]:

from typing import Optional

def get_some_date(some_argument: int=None) -> Optional[datetime]:
# as defined

From the documentation on typing, Optional is shorthand for:

Optional[X] is equivalent to Union[X, None].

where Union[X, Y] means a value of type X or Y.


If you want to be explicit due to concerns that others might stumble on Optional and not realize it's meaning, you could always use Union:

from typing import Union

def get_some_date(some_argument: int=None) -> Union[datetime, None]:

But I doubt this is a good idea, Optional is an indicative name and it does save a couple of keystrokes.

As pointed out in the comments by @Michael0x2a Union[T, None] is tranformed to Union[T, type(None)] so no need to use type here.

Visually these might differ but programatically, in both cases, the result is exactly the same; Union[datetime.datetime, NoneType] will be the type stored in get_some_date.__annotations__*:

>>> from typing import get_type_hints
>>> print(get_type_hints(get_some_date))
{'return': typing.Union[datetime.datetime, NoneType],
'some_argument': typing.Union[int, NoneType]}

*Use typing.get_type_hints to grab the objects' __annotations__ attribute instead of accessing it directly.

How to type hint a function's optional return parameter?

Since Python 3.10 and PEP 604 you now can use | instead of Union.

The return type would be float | Tuple[float, float]


The right type hint would be:

from typing import Tuple, Union

def myfunc(x: float, return_y: bool = False) -> Union[float, Tuple[float, float]]:
z = 1.5

if return_y:
y = 2.0
return z, y

return z

However, it is usually not a good practice to have these kinds of return. Either return something like Tuple[float, Optional[float]] or write multiple functions, it will be much easier to handle later on.

More about return statement consistency:

  • PEP8 - Programming Recommendations

Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should. If any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable).

  • Why should functions return values of a consistent type?

Type hint for return, return None, and no return at all?

They all should have the -> None return type, since they all clearly return None.

Note that there also exists the typing.NoReturn type for functions that actually never return anything, e.g.

from typing import NoReturn

def raise_err() -> NoReturn:
raise AssertionError("oops an error")

Other types of functions (pointed out by @chepner) that actually never return and thus should be type hinted with -> NoReturn would be for example an event loop that only ends using sys.exit or any of the os.exec* functions

Or should my_func2 or my_func3 have literally no return type hint?

In my opinion, they should always have a type hint, since as @yedpodtrzitko said in their answer, functions with no type hints are by default not type checked by Mypy at all, and their return values are basically treated as if they would've been typed to be Any. This greatly reduces the benefits of type checking, and that's one of the reasons I always use the Mypy setting disallow_untyped_defs = True for new projects.

Python type hinting (for return type) not working for classes vs subclasses?

And the get_data_from_another_service function in caller_function.py
file knows that it should always get UserDataSchema. This is because
of the specific value passed in schema_identifier_param parameter.

This is where it gets wrong. Python does not know your convention that "the specific value passed in schema_identifier_param" results in UserDataSchema always being returned. And you can not easily explain this in type hints system. So what Python is saying is roughly "I do not see why get_data_from_another_service will return UserDataSchema". And Python is absolutely right in this.

(Moreover, your code also does not guarantee this in any way. You return something that is returned by some url, so you have to rely on remote server behavior to make it always return UserDataSchema. This is very very fragile.)

How to specify that return value can either be str or None in the hinting

Using Tuple[str, str], you are indicating that this method always returns a tuple of strings.

Instead you can use:
def process(self) -> Tuple[Optional[str], Optional[str]]:

or alternatively:
def process(self) -> Tuple[Union[str, None], Union[str, None]]:

How to write type hints for a function returning itself?

I think @chepner's answer is great. If you really do want to express this as a recursive Callable type, then you could restructure the function as a callable class and do something like this:

from __future__ import annotations

class F:
def __call__(self) -> F:
return self

f = F()

You can test this with mypy to see that it maintains its type on future calls:

g = f()
h = g(1) # Too many arguments for "__call__" of "F"
i = h()
j = i(2) # Too many arguments for "__call__" of "F"
k = j()

How can I specify the function type in my type hints?

As @jonrsharpe noted in a comment, this can be done with typing.Callable:

from typing import Callable

def my_function(func: Callable):

Note: Callable on its own is equivalent to Callable[..., Any].
Such a Callable takes any number and type of arguments (...) and returns a value of any type (Any). If this is too unconstrained, one may also specify the types of the input argument list and return type.

For example, given:

def sum(a: int, b: int) -> int: return a+b

The corresponding annotation is:

Callable[[int, int], int]

That is, the parameters are sub-scripted in the outer subscription with the return type as the second element in the outer subscription. In general:

Callable[[ParamType1, ParamType2, .., ParamTypeN], ReturnType]


Related Topics



Leave a reply



Submit