Type Hints
All values in Python have a type, e.g., 6
has type int
(short for integer),
and 'seven'
has type str
(short for string). 6.7
is a float
, short for
floating point, which means a number that has a decimal point. The
built-in type
function returns the type of its argument.
>>> type(1)
<class 'int'>
>>> type('seven')
<class 'str'>
>>>> type(lambda x: x + 1)
<class 'function'>
Python is dynamically typed, which means that names (also known as variables) do not have types. A name can be assigned to a value of one type and later assigned to a value of a different type:
>>> x = 6
>>> x = 'seven'
This behavior contrasts with statically typed languages such as Java, in which variables have fixed types.
When you're writing code, it's often useful to give a hint to readers about what type of value a name is expected to have. If you're writing a function that will be used by others, describing the expected type of each parameter and the return value is helpful documentation. Type checking, which is a process that ensures that the values assigned to variables have the expected type, can also be very useful for finding bugs. As a result of these benefits, Python programs commonly include type hints, which allow you to describe the expected type for variables in your code.
A type hint for a single variable looks like a colon after the variable name, followed by the expected type:
x: int = 6
y: string = "seven"
z: float = 1.5
You can also add type hints for the parameters and return value of a function:
def fibonacci(n: int) -> int:
...
In fibonacci
above, The input parameter n
is expected to have type int
.
The arrow (->
) is part of the type hint for the return value, and -> int
means that this function is expected to return an int
.
A type hint for a list can just be list
, but if the items in the list are all
meant to have the same type, then the hint can include the type of the items as
well. For example, list[int]
describes a list of integers, and list[str]
is
a list of String values.
s: list = [1, 'two', 3.0]
t: list[int] = [4, 5]
u: list[float] = [6.7]
Python's interpreter does not enforce that a name can only be bound to values that have the type in the hint, so this code will run without an error:
>>> x: int = 'not an int'
>>> x
'not an int'
>>> type(x)
<class 'str'>
Above, when we call type(x)
, we're not finding the type of the variable x
because variables don't have types! Instead, we're finding the type of the value
of x
. That's because to evaluate a call expression, Python evaluates the
operands before applying the function. So, to evaluate type(x)
, Python first
evaluates x
to the string 'not an int'
, and then takes the type of
'not an int'
.
Given that Python doesn't enforce type hints when running a program, you may be
wondering why they're useful at all! One reason is that type hints are great
documentation. They're also useful because type checkers like pyright
and
mypy
will check the types in a program and tell you when a type hint won't
match the actual value type. Type checking is often a useful way to find bugs.
We won't always use type hints for code in this class, and we will not enforce that your code uses type hints. We will try to use them in places where we think they will be helpful to you! You'll also notice them commonly in Python code you find on the web.