What’s special about types in Python?

Reflections on the second chapter of Patrick Viafore’s recent book, ‘Robust Python’. We learn about types and how they fit into Python.

Alex Strick van Linschoten


December 30, 2021

The first section of Robust Python dives into types. We begin by taking a step back to think about what exactly types are being used for, and what they might bring us. Python was not (until v3.5) a language with which you could easily use typing. I remember going to the Pylondinium conference in London in 2018 and going to a talk by Bernat Gabor about type hints in Python. Back then I didn’t have much of a sense of how new they were to many people, but even now I don’t get the feeling that they’ve been universally adopted. Hence Patrick’s book, I suppose…

A type is defined in the book as being “a communication method”, both to / for computers (“mechanical representation”) as well as for humans (“semantic representation”). For the computer, when a variable is of a certain type this determines what methods can be called on that particular object. As such, though I’m straying into territory I don’t fully understand, I believe it also helps with compilation efficiency. (Python is a dynamically-typed language so any errors or type mismatches will only become apparent at runtime, however).

For humans, types can help signal intent. This connects with my previous chapter summary from this book where I stated that code should communicate intent well to be considered ‘robust’. Take the following simple code snippet:

dates = [...]

def process_date(input):
  date = extract_date(input)
  return date

We have an extract_date function (defined elsewhere in the code), but we have no real sense of what this input parameter would be. Are we taking in strings as input? Are we taking in datetime.datetime objects? Does the extract_date function accept both, or do we need to ensure that we are only taking a specific type? All these questions could be cleared up with a simple type hint as part of the function definition, like so:

dates = [...]

def process_date(input: datetime.datetime):
    date = extract_date(input)
  return date

Now we know what the input should be, and we can also add a type hint to the extract_date function as well which will help communicate our intent.

We also learn how Python is more towards the ‘strongly-typed’ side of things on the language spectrum. If you try to concatenate a list with a dict in Python using the + operator, Python will throw a TypeError and fail. If you try to do the same in Javascript you get two different answers depending on the order of the two operands:

>>> [] + {}
"[object Object]"

>>> {} + []

For our purposes, using Python, we can use the strong typing to our advantage.

Python is dynamically typed, though, which takes a bit more caution to handle in a robust manner. Any type mismatches will only be found at runtime — at least using just the vanilla install of the language without any extra imports or modules.

The chapter ends with a brief discussion of duck typing, defined as “the ability to use objects and entities in a programming language as long as they adhere to some interface”. We gain a lot in terms of increased composability, but if you rely on this feature of the language too much then it can become a hindrance in terms of communicating intent.

This chapter didn’t add too many new concepts or skills to my current understanding of the benefits of types, but it was useful to have this concept of ‘communicating intent’ to be reiterated. When I think back to how I’ve heard types mentioned in the past, they often get cast in a technical sense, whereas thinking about communication between developers I think is a more motivating framing.