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.
You are always returning one object; using return one, two
simply returns a tuple.
So yes, -> Tuple[bool, str]
is entirely correct.
Only the Tuple
type lets you specify a fixed number of elements, each with a distinct type. You really should be returning a tuple, always, if your function produces a fixed number of return values, especially when those values are specific, distinct types.
Other sequence types are expected to have one type specification for a variable number of elements, so typing.Sequence
is not suitable here. Also see What's the difference between lists and tuples?
Tuples are heterogeneous data structures (i.e., their entries have different meanings), while lists are homogeneous sequences. Tuples have structure, lists have order.
Python's type hint system adheres to that philosophy, there is currently no syntax to specify an iterable of fixed length and containing specific types at specific positions.
If you must specify that any iterable will do, then the best you can do is:
-> Iterable[Union[bool, str]]
at which point the caller can expect booleans and strings in any order, and of unknown length (anywhere between 0 and infinity).
Last but not least, as of Python 3.9, you can use
-> tuple[bool, str]
instead of -> Tuple[bool, str]
; support for type hinting notation has been added to most standard-library container types (see PEP 585 for the complete list). In fact, you can use this as of Python 3.7 too provided you use the from __future__ import annotations
compiler switch for your modules and a type checker that supports the syntax.
Best Answer
From the documentation - Union Type:
This use of
|
was added in Python 3.10. Hence the proper way to represent more than one return data type is:For earlier versions, use
typing.Union
:But do note that typing is not enforced. Python continues to remain a dynamically-typed language. The annotation syntax has been developed to help during the development of the code prior to being released into production. As PEP 484 states, "no type checking happens at runtime."
As you can see I am passing an int value and returning a str. However the
__annotations__
will be set to the respective values.Please go through PEP 483 for more about Type hints. Also see What are type hints in Python 3.5??
Kindly note that this is available only for Python 3.5 and upwards. This is mentioned clearly in PEP 484.