Type Hinting

Type Hints were added to python 3.5 as a way of adding support for linters and 3rd party tools to check code for possible errors. These have no effect of the running of the code and are not mandatory, however they are good software engineering practice and we encourage their use throughout your code.

Example file

#!/usr/bin/env python

import cmath


def quadratic_roots(a, b, c):
    """calculate the quadratic roots of a, b, and c are coefficient and real numbers and also a ≠ 0.
    If a is equal to 0 that equation is not valid quadratic equation.

    Parameters
    ----------
    a : number
    b : number
    c : number

    Returns
    -------
        first : number
        second : number
    Raises
    ------
        ValueError if a == 0
    """
    if a == 0:
        raise ValueError

    discriminant = (b**2) - (4 * a * c)

    first = (-b - cmath.sqrt(discriminant)) / (2 * a)
    second = (-b + cmath.sqrt(discriminant)) / (2 * a)
    return first, second

# This will return a complex result
a, b = quadratic_roots(2, 3, 4)
print(f"{a} {b}")
# This will return a complex but with zero j
a, b = quadratic_roots(1, 4, 2)
print(f"{a} {b}")

# This will throw an exception
try:
    a, b = quadratic_roots(0, 4, 2)
    print(f"{a} {b}")
except ValueError:
    print("a was zero!")

a, b = quadratic_roots("1", "4", "2")
print(f"{a} {b}")

if we run this program we get an error

./function.py
(-0.75-1.1989578808281798j) (-0.75+1.1989578808281798j)
(-3.414213562373095+0j) (-0.5857864376269049+0j)
a was zero!
Traceback (most recent call last):
  File "/Volumes/teaching/Code/ASEAIM/Lab2/./function.py", line 49, in <module>
    a, b = quadratic_roots("1", "4", "2")
  File "/Volumes/teaching/Code/ASEAIM/Lab2/./function.py", line 27, in quadratic_roots
    discriminant = (b**2) - (4 * a * c)
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

We can also run mypy on it which reports

 mypy function.py
Success: no issues found in 1 source file

Adding Type Hints

from typing import Any, Tuple


# Note float type hint will also support int as a number
def quadratic_roots(
    a: float, b: float, c: float
) -> Tuple[Any[float, complex], Any[float, complex]]:

The function has now added type hints for the parameters as well as the return type. Running the new program still causes the same errors with the string parameters however running mypy on the file gives the following.

mypy functionTypeHint.py
functionTypeHint.py:53: error: Argument 1 to "quadratic_roots" has incompatible type "str"; expected "float"
functionTypeHint.py:53: error: Argument 2 to "quadratic_roots" has incompatible type "str"; expected "float"
functionTypeHint.py:53: error: Argument 3 to "quadratic_roots" has incompatible type "str"; expected "float"
Found 3 errors in 1 file (checked 1 source file)

These errors will usually show in vscode if we setup the python tools to use mypy (or pylance).

Stub Files

It is also possible to add type hints to a separate file called a “stub file” typically this will have the extension .pyi

from typing import Any, Tuple

# Note float type hint will also support int as a number
def quadratic_roots(
    a: float, b: float, c: float
) -> Tuple[Any[float, complex], Any[float, complex]]: ...

Stub files only work with imported modules so we can test using a simple file.

#!/usr/bin/env python

from functionStubFile import quadratic_roots

# This will return a complex result
a, b = quadratic_roots(2, 3, 4)
print(f"{a} {b}")
# This will return a complex but with zero j
a, b = quadratic_roots(1, 4, 2)
print(f"{a} {b}")

# This will throw an exception
try:
    a, b = quadratic_roots(0, 4.2, 2)
    print(f"{a} {b}")
except ValueError:
    print("a was zero!")

a, b = quadratic_roots("1", "4", "2")
print(f"{a} {b}")

Running the following now spots the errors

mypy testStubFile.py
testStubFile.py:20: error: Argument 1 to "quadratic_roots" has incompatible type "str"; expected "float"
testStubFile.py:20: error: Argument 2 to "quadratic_roots" has incompatible type "str"; expected "float"
testStubFile.py:20: error: Argument 3 to "quadratic_roots" has incompatible type "str"; expected "float"
Found 3 errors in 1 file (checked 1 source file)

Reading

https://samgeo.codes/blog/python-types/