Ordered Collections, Two Ways
Python gives you two ways to hold an ordered group of things, and the difference is not the brackets. Try to change a tuple the way you would a list, and read exactly what it refuses, and why.
Python gives you two ways to hold an ordered group of things, and the difference is not the brackets. Try to change a tuple the way you would a list, and read exactly what it refuses, and why.
An ordered collection you can change
A list holds items in order, and you can add to it, remove from it, or replace an item at a position, all after it already exists.
$ >>> fruit = ["apple", "banana"]$ >>> fruit.append("cherry")$ >>> fruit$ ['apple', 'banana', 'cherry']$ >>> fruit[0] = "avocado"$ >>> fruit$ ['avocado', 'banana', 'cherry']Nothing requires the items in a list to share a type — [1, "two", 3.0] is a perfectly ordinary list of three items, an int, a string, and a float, all in the same one. Python does not check or care; it only cares that the list itself stays ordered and stays a list.
The same idea, deliberately locked
A tuple looks almost identical — ordered, indexable, written with () instead of [] — except that once it is created, it cannot be changed at all.
numbers = [1, 2, 3]
A list changes size in place.
numbers = (1, 2, 3)
A tuple never changes size.
Why the distinction is worth keeping
A tuple being locked is not a missing feature, it is the point. A function that returns a pair of coordinates, (x, y), returns a tuple on purpose — nothing downstream can accidentally reorder or extend it, because nothing downstream is allowed to touch it at all.
As a rule of thumb: reach for a tuple when the number of items is fixed by what the data is — a coordinate is always two numbers, a date is always three. Reach for a list when the number of items is expected to change while the program runs.
The copy-versus-reference trap
You already know from the earlier lesson on variables that a name points at a value, it does not hold a copy of one. Lists make the consequence hard to miss: assigning one list to a second name never copies it, no matter how much the assignment looks like it should.
$ >>> original = [1, 2, 3]$ >>> copy = original$ >>> copy.append(4)$ >>> original$ [1, 2, 3, 4]copy was never a copy. It is a second name on the same list, so changing it through one name is visible through the other. The same trap reappears the moment you hand a list to a function — the parameter inside the function is another name on your original list, not a private version of it.
$ def add_bonus(scores): scores.append(100) $ results = [88, 92, 79]$ add_bonus(results)$ print(results)# [88, 92, 79, 100]Nothing about add_bonus looks dangerous, and the effect on results was not written anywhere in the calling code. If you meant to work on a private copy, you have to ask for one explicitly — there are three equivalent ways.
$ >>> original = [1, 2, 3]$ >>> safe = original.copy()$ >>> safe = list(original)$ >>> safe = original[:]$ >>> safe.append(4)$ >>> original$ [1, 2, 3]Methods that return something, and the one that does not
A list comes with a handful of methods that change it in place. Most of them hand you something useful back as well — except the one every beginner eventually assigns away by accident.
Adds x to the end. Returns None — the list itself changes in place.
Removes and returns the last item, or the item at a given index.
Removes the first x it finds. Returns None. Raises ValueError if x is not there.
Sorts the list in place. Returns None — never assign a list to the result of calling this.
Returns how many times x appears, without changing the list at all.
The safe alternative already has a different name, on purpose: the built-in sorted() function.
sorted(numbers)
Returns a brand new sorted list and leaves the original untouched. Always safe to write numbers = sorted(numbers).
numbers.sort()
Sorts the existing list in place and returns None. Call it on its own line — never assign its result back to anything.
Key takeaways
- Lists and tuples are both ordered — the difference is that a list can change size and contents, a tuple cannot.
- A tuple being unchangeable is deliberate: it guarantees nothing downstream can alter what you handed it.
- Assigning a list to a new name never copies it. Use .copy(), list(x), or x[:] when you actually need a separate list.
- A list passed into a function is the same list, not a private copy — changes made inside are visible after the call returns.
- sort() mutates in place and returns None. sorted() returns a new sorted list and leaves the original alone — never assign the first one to a name.
Quick check
Answer these to unlock the next chapter — 3 of 4 to pass. You can retake it anytime.
Answer every question to check.
Make a free account to read on
Every chapter is free — an account is how your progress, XP, and streak follow you from your laptop to your phone, and how you show up on the leaderboard. No payment, no trial.