Python Quirks? Party Tricks? Peculiarities Revealed…
Three "weird" Python behaviours that aren't weird at all
"That's weird! Surely it must be a flaw in Python." There are a few seemingly-odd behaviours in Python that elicit this response. It's a rite of passage for those learning Python to get from that sentiment to "That makes perfect sense, yes!"
I've selected three of these Python peculiarities, and I'll explore them in this article, taking you on the journey from "it's weird" to "it's clear".
These are the three oddities:
1. The Self-Replicating Trick
Let's create a list of lists to store members of several teams. You can start by creating a list containing empty lists:
And now, add a team member to the first of these teams:
Bob seems to have self-replicated into all the teams.
2. The Teleportation Trick
Let's create a function to add items to a shopping list. The function has a default value for shopping_list
:
And now, create two shopping lists, one for groceries and one for books:
Bread has somehow teleported from the grocery list to the bookshop list.
3. The Vanishing Trick
Let's collect all the doubles of the numbers from 0
to 9
:
And check whether 4
is in doubles
:
It looks like it was there, but then it vanished.
These are not bugs or oversights by the Python core developers. In all of these three "tricks", the result you see is the expected result. Let's look at each in more detail and dig underneath the surface to explain what's happening.
1. The Self-Replicating Trick
Let's look at the example again:
You start with a list containing an empty list, and you multiply this by 5
. This gives you a list with five lists. Or so it seems.
When you append a name to teams[0]
, you might expect the name "Bob"
to be added to the first of the lists within teams
. However, "Bob"
is added to all the lists.
Let's rewind to the creation of the list of lists:
At first sight, it seems you have five empty lists. Let's print the identities of the lists within teams
using the built-in id()
function:
The same number is printed five times. And if you don't like scanning through those numbers to check they're the same, you can try the following:
The elements of a set are unique, so there's only one number in the set.
If the five lists have the same identity, they must be the same object. There aren't five lists in teams
. Instead, there's one list repeated five times.
A list contains references to other objects. It doesn't contain the objects themselves. When you multiply [[]]
by five, you create five copies of the reference to the inner list. You can confirm that only one inner list is created by disassembling [[]] * 5
into bytecode:
Only two lists are created, the outer and inner lists. Multiplying by 5
doesn't create additional lists. It replicates the references to the list already present.
The alternative
If you want to create a list called teams
that contains five empty lists, you can use a comprehension:
When you use a list comprehension, the creation of a new list is repeated five times. The identities of the five lists are different in this case. You can try adding "Bob"
to the first team now:
On this occasion, "Bob"
is only added to the first list. The name doesn't self-replicate into all the lists.