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 toUnion[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
ormy_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
Pandas Selecting by Label Sometimes Return Series, Sometimes Returns Dataframe
Attributeerror: 'List' Object Has No Attribute 'Click' - Selenium Webdriver
How to Wrap Every Method of a Class
Django Model "Doesn't Declare an Explicit App_Label"
Matching Any Character Including Newlines in a Python Regex Subexpression, Not Globally
All Synonyms for Word in Python
Simple Animation Using Tkinter
I am Sending Commands Through Serial Port in Python But They Are Sent Multiple Times Instead of One
Attributeerror: Can't Set Attribute When Connecting to SQLite Database with Flask-Sqlalchemy
Which Seeds Have to Be Set Where to Realize 100% Reproducibility of Training Results in Tensorflow
Python: Read Lines from Compressed Text Files
Matplotlib Scatter Plot with Legend
Using Self.Xxxx as a Default Parameter - Python
How to Read Unicode Input and Compare Unicode Strings in Python
What's the Difference Between 'R+' and 'A+' When Open File in Python