No Time Dad

A blog about web development written by a busy dad

Python Type Hint for a List of Strings

I was recently re-writing a large shell script in Python and I decided it’d be a good time to try Python’s type hints. I was curious what it would be like after using TypeScript for a while. And I guess I wasn’t too surprised to find that it wasn’t as nice as using TypeScript. But I think Python’s type hints are moving in the right direction.

In the Python script I was working on I needed to create a list of choices for time periods. It needed to look something like this:

VALID_PERIODS = ["latest", "week", "month", "year"]

But I thought it would be nice if VALID_PERIODS was typed and only allowed the values shown above. Luckily, Python has a literal type now that’ll allow me to do just that. I can define a Literal in a list containing all of the values that VALID_PERIODS should allow. It’d look something like the below.

from typing import Literal

PeriodChoices = Literal["latest", "week", "month", "year"]
VALID_PERIODS: list[PeriodChoices] = ["latest", "month", "week", "year"]

I think this is an okay solution, but it’s not great. The problem is that if I needed to add a new period like “daily”, I’d have to add it in two places. In the brief example above the type definition and the variable are right next to each other so it’s not a big deal to make that update, but in a real codebase that’s not likely going to be the case. It would be awesome to be able to have one source of truth for the period values.

It turns out that there is a sort of undocumented method in the typing lib to help with this. That is, the get_args method. I can’t even remember how I stumbled on this, probably StackOverflow. But this method has been helpful for cases like this where I want the values from a Python type definition.

The get_args method returns a tuple by default. In my case I need a list so I just wrapped the method call in Python’s list method to change it to a list instead.

Below is the final solution I came up with for creating a type hint for a list of strings. It requires thinking a little backwards, using the type definition as the source of truth and deriving the values from it using the get_args helper method. But now I only have to update one list instead of two.

from typing import Literal, get_args

PeriodChoices = Literal["latest", "week", "month", "year"]
VALID_PERIODS: list[PeriodChoices] = list(get_args(PeriodChoices))

# ["latest", "week", "month", "year"]