The benefits of trailing commas

Share
Copied to clipboard.
Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
5 min. read 3 min. video Python 3.10—3.14

Let's talk about trailing commas in Python.

What's a trailing comma?

When I'm make a multi-line list, dictionary, tuple or function call (see wrap a long line in Python), I prefer to put the closing bracket or brace on its own line:

fruits = [
    "lemons",
    "pears",
    "jujubes",
    "apples",
    "bananas",
    "blueberries",
    "watermelon",
]

I also usually prefer to put each element on its own line, with a comma after each one, including the last element. This is called a trailing comma.

A trailing comma is not necessary in Python, but it can be helpful.

Swapping items over multiple lines

Let's say we have a dictionary that doesn't use a trailing comma:

inventory = {
    "lemons": 1,
    "pears": 2,
    "apples": 3,
    "bananas": 5
}

We have each element on its own line, but the last one doesn't have a comma after it.

Let's say we swap pears and bananas in this dictionary:

inventory = {
    "lemons": 1,
    "bananas": 5
    "apples": 3,
    "pears": 2,
}

Currently running our code would result in a SyntaxError due to a missing comma.

When swapping these lines we need to be careful to make sure that we add a comma after bananas (because it's now in the middle of this dictionary):

inventory = {
    "lemons": 1,
    "bananas": 5,
    "apples": 3,
    "pears": 2,
}

But for consistency's sake, we should also remove the comma after the last element (now pears), because we're trying to not use trailing commas in our code.

inventory = {
    "lemons": 1,
    "bananas": 5,
    "apples": 3,
    "pears": 2
}

If instead, we decided to embrace trailing commas:

inventory = {
    "lemons": 1,
    "pears": 2,
    "apples": 3,
    "bananas": 5,
}

We could just swap pears and bananas and call it a day:

inventory = {
    "lemons": 1,
    "bananas": 5,
    "apples": 3,
    "pears": 2,
}

We're done at this point! We just swapped two lines without any extra adding or removing of commas.

Adding new items over multiple lines

So trailing commas can be helpful when swapping elements in a multi-line data structure, but they can also be helpful when adding new elements as well.

If we were to add an element in the middle of our data structure (we've added limes here), we would always put a comma at the end:

inventory = {
    "lemons": 1,
    "bananas": 5,
    "limes": 2,
    "apples": 3,
    "pears": 2
}

But if we add an element at the end, when we're not using trailing commas things get a bit trickier.

When adding an element at the end, we shouldn't put a comma at the end (assuming we're trying to avoid trailing commas):

inventory = {
    "lemons": 1,
    "bananas": 5,
    "apples": 3,
    "pears": 2
    "limes": 2
}

But we also need to worry about the line just before the one we added (the line that used to be the last line).

Our previously last line now needs a comma at the end (after pears):

inventory = {
    "lemons": 1,
    "bananas": 5,
    "apples": 3,
    "pears": 2,
    "limes": 2
}

Otherwise we would have a SyntaxError.

If diff our code at this point, we'll see that we didn't just change one line of code, we changed two lines:

$ diff -u --label "Before" before.py --label "After" after.py
--- Before
+++ After
@@ -2,5 +2,6 @@
     "lemons": 1,
     "bananas": 5,
     "apples": 3,
-    "pears": 2
+    "pears": 2,
+    "limes": 2
 }
~/_ $

With trailing commas, we could have just changed one line instead. No matter whether you're adding an element to the middle or the end of a multi-line data structure, with trailing commas you don't need to worry about the neighboring lines of code.

The dangers of implicit string concatenation

Another really good reason to use trailing commas (if you're not convinced at this point) is that they also help avoid a very common Python gotcha.

Here we have a list of strings that's not using a trailing comma:

fruits = [
    'blueberry',
    'clementine',
    'pear',
    'jujube',
    'watermelon',
    'strawberry',
    'lemon',
    'apple'
]

for fruit in fruits:
    print("I like", fruit)

Let's move apple to the beginning of this list:

fruits = [
    'apple'
    'blueberry',
    'clementine',
    'pear',
    'jujube',
    'watermelon',
    'strawberry',
    'lemon',
]

for fruit in fruits:
    print("I like", fruit)

We did it. We're done at this point, right? According to Python, we are!

According to Python, we have a perfectly valid list:

I like appleblueberry
I like clementine
I like pear
I like jujube
I like watermelon
I like strawberry
I like lemon

But the first element is appleblueberry, which is not what we were looking for!

Python is using implicit string concatenation here. If two string literals are sitting next to each other, Python will concatenate them for you automatically (as if they had a + symbol between them).

This is a Python feature that's also a bug waiting to happen.

If we had been using a trailing comma and we swapped these two lines of code, we wouldn't have been bit by implicit string concatenation.

Trailing commas: easier diffs and fewer bugs

When breaking a data structure or a function call over multiple lines in Python, it's recommended to use a trailing comma. Trailing commas make for: easier code changes, shorter diffs, and fewer bugs.

A Python Tip Every Week

Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.