Sitemap
Ajay Narayan

Ajay Narayan

Just a Python enthusiast sharing what I learn and discover along the way.

Python Tuples and Sets: The Two Collections Beginners Skip (But Shouldn’t)

9 min readOct 29, 2026

--

One can’t be changed. The other can’t hold duplicates. Both will make your code cleaner.

Press enter or click to view image in full size

Hey again! 👋

Remember this line from the dictionaries post?

Keys must be unchangeable types, usually strings or numbers. You can’t use a list as a key.

You might be wondering: “So what CAN I use if my key has more than one part?” Like a location with a latitude and a longitude?

Great question. The answer is a tuple.

And while we’re at it, there’s another question hiding in our past projects. In the loops post, our contact list could contain "Alice" twice. In the lists post, one of the challenges was removing duplicates by hand with a loop. What if Python could just… refuse to store duplicates in the first place?

That’s a set.

Today we finish your collection toolkit. After this post, you’ll know all four of Python’s core collections: lists, dictionaries, tuples, and sets. More importantly, you’ll know when to use which.

What You’ll Master Today

By the end of this post, you’ll be able to:

✅ Create tuples and understand why “unchangeable” is a feature, not a limitation

✅ Unpack tuples into variables (including the famous one-line swap)

✅ Return multiple values from a function

✅ Create sets and remove duplicates instantly

✅ Use set math: union, intersection, and difference

✅ Choose the right collection for any job

✅ Build a Playlist Matcher app

Prerequisites: Everything so far, especially Lists, Dictionaries, and Functions.

Part 1: Tuples — Lists That Can’t Change

A tuple looks almost like a list, but uses round brackets instead of square ones:

point = (3, 5)
colors = ("red", "green", "blue")
birthday = (14, "March", 2001)

print(point)
print(type(point))

# Output:
# (3, 5)
# <class 'tuple'>

Everything you learned about reading lists works on tuples too:

colors = ("red", "green", "blue")

print(colors[0])
print(colors[-1])
print(colors[0:2])
print(len(colors))
print("green" in colors)

# Output:
# red
# blue
# ('red', 'green')
# 3
# True

Indexing, negative indexing, slicing, len, in. All the same. So what's different?

Tuples are immutable

Try to change one:

point = (3, 5)
point[0] = 10

# TypeError: 'tuple' object does not support item assignment

No .append(), no .remove(), no .sort(). Once a tuple is created, it stays exactly as it is.

You might be thinking: why would I want something I can’t change?

Because some data shouldn’t change. A date of birth. The coordinates of a city. The RGB values of your brand colour. Days of the week. When you store those in a tuple, you’re telling Python (and every developer who reads your code later): this is fixed, don’t touch it. If someone tries, they get an error instead of a silent bug.

The single-item trap

This one catches everyone exactly once:

not_a_tuple = (5)
a_tuple = (5,)

print(type(not_a_tuple))
print(type(a_tuple))

# Output:
# <class 'int'>
# <class 'tuple'>

Wait, what? It’s the comma that makes a tuple, not the brackets. (5) is just the number 5 in brackets, like in maths. For a one-item tuple, you need that trailing comma: (5,).

Part 2: Tuple Unpacking — Python’s Neat Trick

Here’s where tuples get genuinely fun. You can split a tuple into separate variables in one line:

point = (3, 5)
x, y = point

print(f"x = {x}, y = {y}")

# Output:
# x = 3, y = 5

The number of variables on the left must match the number of items in the tuple. Python pairs them up in order.

The one-line swap

In most languages, swapping two variables needs a temporary third variable. In Python:

a = 10
b = 20

a, b = b, a

print(a, b)

# Output:
# 20 10

What’s happening? b, a on the right builds a tuple (20, 10), and then it's unpacked into a and b. One of my favourite lines in all of Python.

Plot twist: you’ve been using tuples all along

Remember these from earlier posts?

for number, task in enumerate(tasks, start=1):
...

for name, phone in contacts.items():
...

enumerate() and .items() both hand you tuples, and for a, b in ... unpacks them. You've been unpacking tuples for two posts without knowing it!

Returning multiple values from a function

In the functions post, every function returned one thing. But what if you need two answers?

def min_max(numbers):
return min(numbers), max(numbers)

marks = [72, 88, 45, 91, 60]
lowest, highest = min_max(marks)

print(f"Lowest: {lowest}")
print(f"Highest: {highest}")

# Output:
# Lowest: 45
# Highest: 91

return min(numbers), max(numbers) actually returns a single tuple, (45, 91). Then we unpack it into two variables. Clean, readable, and very common in real code.

Tuples as dictionary keys

And here’s the answer to our question from the start. Since tuples can’t change, they can be dictionary keys:

cities = {
(9.93, 76.26): "Kochi",
(12.97, 77.59): "Bengaluru",
(19.08, 72.88): "Mumbai",
}

print(cities[(12.97, 77.59)])

# Output:
# Bengaluru

Try that with a list as the key and Python says TypeError: unhashable type: 'list'. Tuples are welcome; lists aren't.

Part 3: Sets — No Duplicates Allowed

A set is a collection of unique items, written with curly braces:

numbers = {3, 1, 3, 2, 1, 3}
print(numbers)
print(len(numbers))

# Output:
# {1, 2, 3}
# 3

We gave it six numbers. It kept three. Every duplicate was silently dropped. That’s the whole personality of a set.

Two important things to know:

Get Ajay Narayan’s stories in your inbox

Join Medium for free to get updates from this writer.

1. Sets have no order. Don’t count on items coming out in the order you put them in. That also means no indexing:

numbers = {1, 2, 3}
print(numbers[0])

# TypeError: 'set' object is not subscriptable

2. An empty set is set(), not {}. Curly braces on their own make an empty dictionary:

empty_dict = {}
empty_set = set()

print(type(empty_dict))
print(type(empty_set))

# Output:
# <class 'dict'>
# <class 'set'>

Removing duplicates in one line

Remember the “No Duplicates” challenge from the lists post, where you had to loop and check in for every item? Watch this:

visits = ["priya", "rahul", "priya", "sneha", "rahul", "priya"]

unique_visitors = set(visits)

print(f"Total visits: {len(visits)}")
print(f"Unique visitors: {len(unique_visitors)}")

# Output:
# Total visits: 6
# Unique visitors: 3

set() turns any list into a set, and the duplicates disappear. This is exactly how websites count "unique visitors". (Small catch: the original order is lost. If you need the order, the loop from the lists post is still the right tool.)

Adding and removing

tags = {"python", "coding"}

tags.add("beginners")
tags.add("python") # already there, nothing happens
print(len(tags))

tags.remove("coding") # crashes if the item isn't there
tags.discard("java") # does nothing if the item isn't there
print(sorted(tags))

# Output:
# 3
# ['beginners', 'python']

Notice I used sorted() to print. Since sets have no order, sorting them is the easiest way to get predictable output.

And just like dictionary keys, sets can only hold unchangeable things. Numbers, strings and tuples are fine. Lists are not.

Part 4: Set Math — The Superpower

This is where sets really shine. Imagine two classes:

python_class = {"Priya", "Rahul", "Sneha"}
web_class = {"Rahul", "Arjun", "Sneha"}

Now you can ask questions that would take loops and found flags with lists, in one symbol each:

# Who is in BOTH classes?  (intersection)
print(sorted(python_class & web_class))

# Who is in AT LEAST ONE class? (union)
print(sorted(python_class | web_class))

# Who is ONLY in the Python class? (difference)
print(sorted(python_class - web_class))

# Who is in exactly ONE class, not both? (symmetric difference)
print(sorted(python_class ^ web_class))

# Output:
# ['Rahul', 'Sneha']
# ['Arjun', 'Priya', 'Rahul', 'Sneha']
# ['Priya']
# ['Arjun', 'Priya']

A quick way to remember them:

  • & and: in this set and that one
  • | or: in this set or that one (or both)
  • - minus: in this set, minus anything in that one
  • ^ one or the other, but not both

If you prefer words, every symbol has a method too: .intersection(), .union(), .difference(), and .symmetric_difference().

Recommendations (“people who liked this also liked…”), mutual friends, finding missing items between two lists… a surprising amount of real software is just set math.

Part 5: Which Collection Should I Use?

You now know all four. Here’s the cheat sheet I wish I’d had as a beginner:

  • List [ ]: an ordered collection you'll change. Shopping cart, to-do list, scores.
  • Tuple ( ): an ordered collection that shouldn't change. Coordinates, dates, RGB colours, returning multiple values.
  • Set { }: unique items where order doesn't matter. Tags, unique visitors, "who's in both groups?"
  • Dictionary {key: value}: look things up by name. Contacts, prices, settings, counting.

Not sure? Ask yourself two questions:

  1. Do I look things up by name? → dictionary
  2. Do duplicates matter? No → set. Yes → list (or tuple if it never changes)

Mini Project: Playlist Matcher 🎵

Time to put sets (and a little tuple unpacking) to work. You and a friend each type your favourite songs, and the app tells you what you have in common:

def get_songs(person):
raw = input(f"{person}, enter your favourite songs (comma-separated): ")
songs = set()
for song in raw.split(","):
song = song.strip().title()
if song:
songs.add(song)
return songs

def compare(you, friend):
return you & friend, you - friend, friend - you

def show(title, songs):
print(f"\n{title} ({len(songs)}):")
if not songs:
print(" (none)")
for song in sorted(songs):
print(f" - {song}")

def main():
print("=" * 50)
print("PLAYLIST MATCHER")
print("=" * 50)

you = get_songs("You")
friend = get_songs("Friend")

both, only_you, only_friend = compare(you, friend)
everything = you | friend

show("You both like", both)
show("Only you like", only_you)
show("Only your friend likes", only_friend)
show("Combined playlist", everything)

if everything:
score = len(both) / len(everything) * 100
else:
score = 0
print(f"\nMusic match score: {score:.0f}%")

main()

# Example run:
# You, enter your favourite songs (comma-separated): believer, shape of you, perfect
# Friend, enter your favourite songs (comma-separated): Perfect, BELIEVER, senorita
#
# You both like (2):
# - Believer
# - Perfect
#
# Only you like (1):
# - Shape Of You
#
# Only your friend likes (1):
# - Senorita
#
# Combined playlist (4):
# - Believer
# - Perfect
# - Senorita
# - Shape Of You
#
# Music match score: 50%

A few things worth noticing:

  • .strip().title() is the same clean-up trick from the contact book. It's why "BELIEVER" and "believer" count as the same song.
  • compare() returns three sets at once as a tuple, and both, only_you, only_friend = ... unpacks them. Tuples and sets working together.
  • The match score is the size of the intersection divided by the size of the union. Fun fact: that’s a real formula called the Jaccard similarity, and it’s used in actual recommendation systems.

Practice Challenges

Beginner Level

  1. Fixed Favourites: Make a tuple of your 3 favourite foods. Print each one with a for loop. Then try to change one, and read the error message.
  2. Duplicate Cleaner: Turn [1, 2, 2, 3, 3, 3, 4] into a set and print how many unique numbers there are.

Intermediate Level

  1. Stats Function: Write stats(numbers) that returns the minimum, maximum, and average as a tuple. Unpack the result into three variables and print them.
  2. Unique Letters: Ask for a word and print how many different letters it has. ("banana" has 3: b, a, n.) Hint: set(word).

Advanced Level

  1. Pangram Checker: A pangram uses every letter of the alphabet at least once, like “The quick brown fox jumps over the lazy dog.” Write a function that returns True if a sentence is a pangram. (Hint: build a set of the lowercase letters in the sentence and compare its size to 26. Watch out for spaces and punctuation!)

Before You Go

Did tuples and sets click for you? Hit that 👏 clap button.

Built the Playlist Matcher? Run it with a friend and drop your match score in the comments. Let’s see who has the most similar music taste. 🎧

Coming up next: Strings, properly. You’ve already used .strip(), .title() and .split() without me ever explaining them. Next time, we dig into all the powerful things Python can do with text. Hit Follow so you don't miss it.

See you in the next post! 🐍✨

Enjoying this series? Share it with a friend learning Python. Let’s all grow faster, together.

Check out the series so far:

--

--

Written by Ajay Narayan

Just a Python enthusiast sharing what I learn and discover along the way.