List or Tuple: Which One Should You Use?(Python Core in Action 3)
Unlocking Python: The Essential Guide to Lists and Tuples
Data structures are the foundation of every programming language.
Understanding Python's basic data structures is crucial for mastering the language.
Today, let's learn about two of the most common data structures in Python: lists and tuples.
Lists and Tuples Basics
First, let's understand the basics: what are lists and tuples?
Both are ordered collections that can hold any data type.
In most programming languages, collections must have uniform data types. However, Python lists and tuples do not have this requirement.
l = [1, 2, 'hello', 'world'] # The list contains both int and string elements
l
[1, 2, 'hello', 'world']
tup = ('jason', 22) # The tuple contains both int and string elements
tup
('jason', 22)
Next, we need to know their differences.
Lists are dynamic and mutable, meaning their size can change, and you can add, remove, or modify elements.
Tuples are static and immutable, meaning their size is fixed, and you cannot change their elements.
In the examples below, we create a list and a tuple.
For the list, we can easily change the last element from 4 to 40. Trying the same with a tuple will result in an error because tuples are immutable.
l = [1, 2, 3, 4]
l[3] = 40 # Similar to many languages, Python indexing starts at 0. l[3] accesses the fourth element of the list
l
[1, 2, 3, 40]
tup = (1, 2, 3, 4)
tup[3] = 40
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
So, what if you need to "change" a tuple?
You would need to create a new tuple.
For example, to add an element 5 to a tuple, you create a new tuple with the existing values and the new element.
For lists, simply append the new element to the end.
These examples show the basic concepts of lists and tuples.
tup = (1, 2, 3, 4)
new_tup = tup + (5, ) # Create a new tuple new_tup and fill it with the values of the original tuple
new_tup
(1, 2, 3, 4, 5)
l = [1, 2, 3, 4]
l.append(5) # Add element 5 to the end of the original list
l
[1, 2, 3, 4, 5]
Now, let's look at some basic operations and tips for lists and tuples.
Unlike other languages, Python lists and tuples support negative indexing: -1 is the last element, -2 is the second-to-last, and so on.
l = [1, 2, 3, 4]
l[-1]
4
tup = (1, 2, 3, 4)
tup[-1]
4
Besides initialization and indexing, both lists and tuples support slicing.
l = [1, 2, 3, 4]
l[1:3] # Returns a sublist from index 1 to 2
[2, 3]
tup = (1, 2, 3, 4)
tup[1:3] # Returns a subtuple from index 1 to 2
(2, 3)
They can also be nested.
l = [[1, 2, 3], [4, 5]] # Each element of the list is also a list
tup = ((1, 2, 3), (4, 5, 6)) # Each element of the tuple is also a tuple
Additionally, you can convert between lists and tuples using the list() and tuple() functions.
list((1, 2, 3))
[1, 2, 3]
tuple([1, 2, 3])
(1, 2, 3)
Lastly, let's look at some common built-in functions for lists and tuples:
l = [3, 2, 3, 7, 8, 1]
l.count(3)
2
l.index(7)
3
l.reverse()
l
[1, 8, 7, 3, 2, 3]
l.sort()
l
[1, 2, 3, 3, 7, 8]
tup = (3, 2, 3, 7, 8, 1)
tup.count(3)
2
tup.index(7)
3
list(reversed(tup))
[1, 8, 7, 3, 2, 3]
sorted(tup)
[1, 2, 3, 3, 7, 8]
`count(item)`: Counts the occurrences of items in the list or tuple.
`index(item)`: Returns the first index of item in the list or tuple.
`list.reverse()`: Reverses the list in place (not available for tuples).
`list.sort()`: Sorts the list in place (not available for tuples).
`reversed()`: Returns an iterator that reverses the list or tuple.
`sorted()`: Returns a new sorted list from the list or tuple.
Differences in Storage Between Lists and Tuples
As mentioned earlier, the main difference between lists and tuples is that lists are dynamic and mutable, while tuples are static and immutable. This difference affects how they are stored. Let's look at an example:
l = [1, 2, 3]
l.__sizeof__()
64
tup = (1, 2, 3)
tup.__sizeof__()
48
For both lists and tuples with the same elements, tuples use 16 bytes less space than lists. Why?
Since lists are dynamic, they need to store pointers to their elements (8 bytes for each int in our example).
Additionally, because lists can change size, they need to store their allocated length (8 bytes) to track their usage and allocate extra space when needed.
l = []
l.__sizeof__() # The storage space of an empty list is 40 bytes
40
l.append(1)
l.__sizeof__()
72 # After adding element 1, the list allocates space for 4 elements (72 - 40)/8 = 4
l.append(2)
l.__sizeof__()
72 # The list space remains the same since it already has allocated space
l.append(3)
l.__sizeof__()
72 # Same as above
l.append(4)
l.__sizeof__()
72 # Same as above
l.append(5)
l.__sizeof__()
104 # After adding element 5, the list runs out of space and allocates space for 4 more elements
The example shows how list space allocation works.
To reduce the overhead of frequent space allocations when adding or removing elements, Python over-allocates space, ensuring efficient operations with a time complexity of O(1) for additions and deletions.
Tuples are different. Their length and elements are fixed, so their storage space is fixed.
You might think this difference is negligible.
But imagine if a list or tuple stores a billion elements or more. Can you still ignore this difference?
Performance of Lists and Tuples
By studying the storage differences between lists and tuples, we see that tuples are lighter. So, tuples generally perform slightly better than lists.
Python also uses resource caching for static data in the background.
Due to garbage collection, Python returns the memory of unused variables to the OS for other uses.
But for static variables like tuples, if not used and small in size, Python caches this memory.
Next time a tuple of the same size is created, Python can allocate the cached memory instead of requesting new memory from the OS, speeding up the program.
Here's an example that measures the time to initialize a list and a tuple with the same elements. Tuples initialize 5 times faster than lists.
python3 -m timeit 'x=(1,2,3,4,5,6)'
20000000 loops, best of 5: 9.97 nsec per loop
python3 -m timeit 'x=[1,2,3,4,5,6]'
5000000 loops, best of 5: 50.1 nsec per loop
However, for indexing, the speed difference is minimal and can be ignored.
python3 -m timeit -s 'x=[1,2,3,4,5,6]' 'y=x[3]'
10000000 loops, best of 5: 22.2 nsec per loop
python3 -m timeit -s 'x=(1,2,3,4,5,6)' 'y=x[3]'
10000000 loops, best of 5: 21.9 nsec per loop
If you need to add, remove, or change elements, lists are better. As you now know, changing a tuple requires creating a new one.
Use Cases for Lists and Tuples
When should you use a list or a tuple? Let's analyze them based on their characteristics.
1. If the data and its size do not change, like a function returning the coordinates of a location for front-end rendering, use a tuple.
def get_location():
.....
return (longitude, latitude)
2. If the data or its size can change, like a social media log tracking posts a user views in a week, use a list.
viewer_owner_id_list = [] # Each element records all owner IDs viewed by this viewer within a week
records = queryDB(viewer_id) # Query the database to get the logs of a viewer for a week
for record in records:
viewer_owner_id_list.append(record.id)
Conclusion
We discussed a lot about lists and tuples. Here's a summary of what you need to know.
Lists and tuples are ordered collections that can store any data type. Their main differences are:
Lists are dynamic and mutable. You can change their size and elements. Lists use more storage space and have slightly lower performance than tuples.
Tuples are static and immutable. You cannot change their size or elements. Tuples are lighter and perform slightly better than lists.
Excited to read it! Will be very helpful!
I just learned about Tuples yesterday! Thanks for helping me reinforce what I learned!