Towards type safety: Adding type hints (annotations) to Python code

Towards type safety: Adding type hints (annotations) to Python code

Like many interpreted languages, Python is a "duck typed" language: so when using an object, if it "walks like a duck, talks like a duck", then you can assume it is safe enough to treat it as a duck.

Examples of applying Duck typing:

class Duck:
    def quack():
        return "quack!"
    def fly():
        return "flying!"

If we have an object, and it happens to have a quack() method and a fly() method, then we can treat it as a Duck:

something.quack()

Another example:

class Dog:
    def bark():
        return "woof!"

Alternatively, if an object has no quack() method, but has a bark() method, then we can assume it is a Dog:

something.bark()


Whilst there is some debate as to whether strongly typed languages are less buggy (the evidence is not clear), it can even help to have some "cosmetic" indications as to what type you are (probably) dealing with.

Python type hints are such a "cosmetic" indication to help simplify working with code.

In particular for library or module publishers, it can be nice to publish type hints with your code, to make it that bit easier to consume.

With Python 3.5, a typing module is available to allow for 'type hints' (basic type annotations) on your Python code.


What is a type hint?

A type hint is some 'sugar' to enable a human coder, or an IDE, or a lint tool to better guess exactly what type a particular element is.

Note: the type hint is NOT enforced by the interpreter.

The elements that can have hints include:

- method return type

- parameter type


Example

As an example, let's look at a simple method, BEFORE and AFTER adding type hints:

BEFORE adding type hints (plain old Python):

def greeting(name):
    return 'Hello ' + name

AFTER adding type hints:

def greeting(name: str) -> str:
    return 'Hello ' + name

Now, as a coder I can more quickly determine the expected type of the 'name' parameter, and the expected return type of the function.

The Any type

If a parameter type is a "known unknown" then we can explicitly indicate that, using the Any type:

from typing import Any

def is_numeric(x: Any) -> bool:
return isinstance(x, numbers.Number)

Here, the parameter 'x' has a type Any, to show the function can accept any kind of object.


How useful is it?

For Visual Code users with Pylance and Python extensions (freely available from Microsoft), this feature does not seem vital, since Visual Code is smart enough to figure out the type and provide a tooltip:


Having said that, the ability to simply read the type hint is nice, and in particular the return type can be useful to read, for more complex functions.

When to use it

Whilst adding type hints may seem a chore, it does seem useful for:

- public interfaces of libraries

- return types from 'public' methods of a module

- return types from complex methods


References

- the typing module

- the mypy static type checker


Comments