Parentheses Do Not a Tuple Make

Ben Cook • Posted 2017-02-04 • Last updated 2021-10-15

The problem

Tuples are immutable sequences in Python. One common way to create a tuple is to put comma separated values in between parentheses.

some_tuple = (1, 2, 3)

There are a few circumstances where you might prefer an immutable sequence over a mutable one, like a list. One reason they can be useful is for holding the arguments to a function.

Let’s say you want to write a threaded function that prints its argument every second for 10 seconds. You might do something like the following:

import time
import threading

def print_forever(some_value):
  for _ in range(10):
      print(some_value)
      time.sleep(1)

args_tuple = (1)
thread = threading.Thread(target=print_forever, args=args_tuple)

But this example is wrong in a subtle way and throws an exception.

>>> thread.start()

Exception in thread Thread-65:
Traceback (most recent call last):
  File "/Users/jbencook/anaconda3/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/Users/jbencook/anaconda3/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
TypeError: print_forever() argument after * must be an iterable, not int

The fix

In the above example, args_tuple isn’t really a tuple. To fix it, you need to change that line.

args_tuple = (1,)

The reason

Why would Python do this? One reason is that parentheses allow you to write multi-line statements without the annoying backslash as a line-continuation character.

this_is_valid = (
   2 +
   2
)
print(this_is_valid)

For strings, you’re not even required to have the plus operator.

important_message = (
   "hello "
   "world"
)
>>> print(important_message)
hello world

While this is tremendously useful for writing concise code, it means that when you actually want a 1-element tuple, you need to add a comma after the first value.

this_is_a_tuple = (4,)