Collections of Data
A collection is a single object that groups multiple values together, so a whole set of data can be stored in one variable, passed around, and looped over as a unit — instead of juggling a separate variable per value, like you would with the basic types. Python's built-in collections mainly differ along two lines: whether items are ordered by position or looked up by key, and whether the collection is mutable (changeable after creation) or not.
| Type | Example | Access values by | Mutable (changeable after creation) | Duplicates allowed | Use it for |
|---|---|---|---|---|---|
list |
["ball", "burmese"] |
Index | Yes | Yes |
|
tuple |
("ball", "burmese") |
Index | No | Yes |
|
dict |
{"species": "ball", ...} |
Key | Yes | No (keys must be unique) |
|
Lists
A list stores multiple items, in order, inside a single variable.
Lists have three defining traits:
- Ordered — items keep the position you put them in, unless you explicitly reorder them.
- Changeable (mutable) — you can add, remove, or change items after the list is created.
- Allow duplicates — since items are accessed by position, not by value, the same value can appear more than once.
species = ["burmese", "rock", "ball", "blood"]
print(species)
Length
len(species) # 4
len(species) # 4len() returns how many items are in a list, and the count updates automatically as you add or remove items.
species = ["burmese", "rock", "ball"]
print(len(species))
species.append("indian")
print(len(species))
Accessing Items
species[0] # "burmese"
species[-1] # "blood"
species[1:3] # ["rock", "ball"]
species[0] # "burmese"
species[-1] # "blood"
species[1:3] # ["rock", "ball"]Items are accessed by index, starting at 0 for the first item.
Negative indexes count down from the end, starting at -1 for the last item.
A slice list[start:end] returns a new list containing items from start up to (but not including) end.
species = ["indian", "rock", "ball", "burmese", "short tailed", "bornean", "angolan", "blood"]
print(species[0])
print(species[2])
print(species[-1])
print(species[1:3])
print(species[:2])
print(species[3:])
Check if Item in List
"burmese" in species # True
species.index("burmese") # 0
species.count("ball") # 1
"burmese" in species # True
species.index("burmese") # 0
species.count("ball") # 1Use in to check whether a value exists in a list at all.
index() finds the position of the first match; count() counts how many times a value appears.
species = ["indian", "rock", "ball", "burmese", "short tailed", "bornean", "angolan", "blood"]
print("burmese" in species)
print("cobra" in species)
print(species.index("burmese"))
print(species.count("ball"))
Change List Items
species[1] = "carpet" # ["burmese", "carpet", "ball", "blood"]
species[1:3] = ["carpet"] # ["burmese", "carpet", "blood"]
species.insert(1, "carpet") # ["burmese", "carpet", "rock", "ball", "blood"]
species[1] = "carpet" # ["burmese", "carpet", "ball", "blood"]
species[1:3] = ["carpet"] # ["burmese", "carpet", "blood"]
species.insert(1, "carpet") # ["burmese", "carpet", "rock", "ball", "blood"]Assign to an index to change a single item.
Assign to a slice to change a whole range at once — the replacement doesn't need to be the same length.
insert() adds an item at a specific index without overwriting what's already there.
species = ["ball", "burmese", "blood"]
species[1] = "bornean"
print(species)
species = ["ball", "burmese", "blood", "angolan"]
species[1:3] = ["bornean"]
print(species)
species = ["ball", "burmese", "blood"]
species.insert(1, "bornean")
print(species)
Add List Items
species.append("carpet") # ["burmese", "rock", "ball", "blood", "carpet"]
species.insert(0, "carpet") # ["carpet", "burmese", "rock", "ball", "blood"]
species.extend(["carpet", "central african rock"]) # ["burmese", "rock", "ball", "blood", "carpet", "central african rock"]
species.append("carpet") # ["burmese", "rock", "ball", "blood", "carpet"]
species.insert(0, "carpet") # ["carpet", "burmese", "rock", "ball", "blood"]
species.extend(["carpet", "central african rock"]) # ["burmese", "rock", "ball", "blood", "carpet", "central african rock"]append() adds one item to the end of the list.
insert() adds one item at a chosen position.
extend() adds every item from another iterable, one at a time — not the iterable itself.
species = ["ball", "blood"]
species.append("burmese")
print(species)
species = ["ball", "blood"]
species.insert(0, "burmese")
print(species)
species = ["ball", "blood"]
more_species = ["bornean", "angolan"]
species.extend(more_species)
print(species)
Remove List Items
species.remove("rock") # ["burmese", "ball", "blood"]
species.pop() # "blood" (removed and returned)
del species[0] # ["rock", "ball", "blood"]
species.clear() # []
species.remove("rock") # ["burmese", "ball", "blood"]
species.pop() # "blood" (removed and returned)
del species[0] # ["rock", "ball", "blood"]
species.clear() # []remove() deletes the first item that matches a given value.
pop() deletes an item by index and returns it — with no index, it removes the last item.
del removes an item by index, or can delete the entire list.
clear() empties the list but keeps the (now empty) list around.
species = ["ball", "bornean", "burmese"]
species.remove("bornean")
print(species)
species = ["ball", "bornean", "burmese"]
last = species.pop()
print(last)
print(species)
species = ["ball", "bornean", "burmese"]
del species[0]
print(species)
species = ["ball", "bornean", "burmese"]
species.clear()
print(species)
Loop Lists
for s in species: print(s) # burmese rock ball blood
for i, s in enumerate(species): print(i, s) # 0 burmese 1 rock 2 ball 3 blood
i = 0
while i < len(species): print(species[i]); i += 1 # same output as the for loop
for s in species: print(s) # burmese rock ball blood
for i, s in enumerate(species): print(i, s) # 0 burmese 1 rock 2 ball 3 blood
i = 0
while i < len(species): print(species[i]); i += 1 # same output as the for loopThe most common way to loop is directly over the items.
enumerate() gives you the index and the value together, which is handy when you need both.
A while loop works too, if you'd rather manage the index yourself.
species = ["ball", "bornean", "burmese"]
for snake in species:
print(snake)
for index, snake in enumerate(species):
print(index, snake)
i = 0
while i < len(species):
print(species[i])
i += 1
List Comprehension
[s for s in species if len(s) > 4] # ["burmese", "blood"]
[s.title() for s in species] # ["Burmese", "Rock", "Ball", "Blood"]
[s for s in species if len(s) > 4] # ["burmese", "blood"]
[s.title() for s in species] # ["Burmese", "Rock", "Ball", "Blood"]List comprehension builds a new list from an existing iterable in a single line.
The expression part can transform each item, not just filter it.
species = ["indian", "rock", "ball", "burmese", "short tailed", "bornean", "angolan", "blood"]
long_names = [s for s in species if len(s) > 10]
print(long_names)
species = ["ball", "burmese", "blood"]
titled = [s.title() for s in species]
print(titled)
Sort Lists
species.sort() # ["ball", "blood", "burmese", "rock"]
species.sort(reverse=True) # ["rock", "burmese", "blood", "ball"]
sorted(species) # same as sort() above, but returns a new list
species.sort(key=len) # ["rock", "ball", "blood", "burmese"]
species.reverse() # ["blood", "ball", "rock", "burmese"]
species.sort() # ["ball", "blood", "burmese", "rock"]
species.sort(reverse=True) # ["rock", "burmese", "blood", "ball"]
sorted(species) # same as sort() above, but returns a new list
species.sort(key=len) # ["rock", "ball", "blood", "burmese"]
species.reverse() # ["blood", "ball", "rock", "burmese"]sort() sorts a list in place, alphabetically (or ascending, for numbers) by default.
Pass reverse=True to sort in the opposite order.
sorted() does the same job but returns a new list, leaving the original untouched.
A key function controls what each item is sorted by — here, by name length instead of alphabetically.
reverse() is different from sort(reverse=True) — it just flips the current order in place, without sorting.
species = ["ball", "burmese", "blood", "angolan"]
species.sort()
print(species)
species = ["ball", "burmese", "blood", "angolan"]
species.sort(reverse=True)
print(species)
species = ["ball", "burmese", "blood", "angolan"]
result = sorted(species)
print(result)
print(species)
species = ["ball", "burmese", "blood", "angolan"]
species.sort(key=len)
print(species)
species = ["ball", "burmese", "blood", "angolan"]
species.reverse()
print(species)
Copy Lists
same_list = species # same_list and species are the same list — mutating one mutates both
backup = species.copy() # backup is a separate, independent list
same_list = species # same_list and species are the same list — mutating one mutates both
backup = species.copy() # backup is a separate, independent listWriting new_list = old_list does not copy the list — both names point to the same list, so a change through either name shows up in both.
copy() (or list(), or a full slice [:]) makes a real, independent copy.
species = ["ball", "blood"]
same_list = species
same_list.append("burmese")
print(species)
species = ["ball", "blood"]
backup = species.copy()
backup.append("burmese")
print(species)
print(backup)
Join Lists
constrictors + short_tailed # ["ball", "burmese", "sumatran short tailed", "myanmar short tailed"]
constrictors.extend(short_tailed) # constrictors now holds all 4, in place
constrictors + short_tailed # ["ball", "burmese", "sumatran short tailed", "myanmar short tailed"]
constrictors.extend(short_tailed) # constrictors now holds all 4, in placeThe + operator concatenates two lists into a new one.
extend() does the same thing in place, adding onto the first list instead of creating a new one.
constrictors = ["ball", "burmese"]
short_tailed = ["sumatran short tailed", "myanmar short tailed"]
combined = constrictors + short_tailed
print(combined)
constrictors = ["ball", "burmese"]
short_tailed = ["sumatran short tailed", "myanmar short tailed"]
constrictors.extend(short_tailed)
print(constrictors)
Check Type
type(species) # <class 'list'>
list(("burmese", "rock", "ball")) # ["burmese", "rock", "ball"]
type(species) # <class 'list'>
list(("burmese", "rock", "ball")) # ["burmese", "rock", "ball"]A list can hold mixed data types — type() still reports it as one list object.
You can also build a list with the list() constructor instead of square brackets.
python_info = ["ball", 3, True] # name, average length in feet, beginner-friendly
print(python_info)
print(type(python_info))
species = list(("ball", "burmese", "blood"))
print(species)
List Exercises
Details & examples
Each box below is fully editable — write your answer, then click Run.
1. Add an item. Add "blood" to the end of the list.
species = ["ball", "burmese", "bornean"]
# your code here
print(species)
2. Remove an item. Remove "bornean" from the list.
species = ["ball", "bornean", "burmese"]
# your code here
print(species)
3. Sort descending. Sort the list from Z to A.
species = ["ball", "burmese", "blood", "angolan", "bornean"]
# your code here
print(species)
4. List comprehension. Build a list of just the names longer than 10 characters.
species = ["indian", "central african rock", "ball", "south african rock", "blood"]
# your code here
print(long_names)
Show solutions
# 1. Add an item
species = ["ball", "burmese", "bornean"]
species.append("blood")
print(species)
# 2. Remove an item
species = ["ball", "bornean", "burmese"]
species.remove("bornean")
print(species)
# 3. Sort descending
species = ["ball", "burmese", "blood", "angolan", "bornean"]
species.sort(reverse=True)
print(species)
# 4. List comprehension
species = ["indian", "central african rock", "ball", "south african rock", "blood"]
long_names = [s for s in species if len(s) > 10]
print(long_names)
Tuples
A tuple stores multiple items, in order, inside a single variable — written with parentheses instead of square brackets.
Tuples have three defining traits:
- Ordered — items keep the position you put them in.
- Immutable — unlike a list, a tuple can't be changed, added to, or shrunk once created.
- Allow duplicates — the same value can appear more than once.
species = ("burmese", "rock", "ball", "blood")
print(species)
Access Items
species[0] # "burmese"
species[-1] # "blood"
species[1:3] # ("rock", "ball")
species[0] # "burmese"
species[-1] # "blood"
species[1:3] # ("rock", "ball")Tuples use the same index and slice syntax as lists — 0 for the first item, negative indexes count from the end, start:end slices out a sub-tuple.
species = ("burmese", "rock", "ball", "blood")
print(species[0])
print(species[-1])
print(species[1:3])
Check if Item in Tuple
"rock" in species # True
species.count("burmese") # 1
species.index("ball") # 2
"rock" in species # True
species.count("burmese") # 1
species.index("ball") # 2Use in to check whether a value exists in the tuple.
count() counts how many times a value appears; index() finds the position of the first match — a tuple has only these two methods, since it can't be changed.
species = ("burmese", "rock", "ball", "blood")
print("rock" in species)
print("cobra" in species)
print(species.count("burmese"))
print(species.index("ball"))
Unpacking
a, b, c, d = species # a="burmese" b="rock" c="ball" d="blood"
a, b, c, d = species # a="burmese" b="rock" c="ball" d="blood"Unpacking assigns each item in a tuple to its own variable in one line — the number of variables has to match the number of items.
species = ("burmese", "rock", "ball", "blood")
a, b, c, d = species
print(a, b, c, d)
Work Around Immutability
species + ("carpet",) # ("burmese", "rock", "ball", "blood", "carpet")
tuple(list(species) + ["carpet"]) # same result, via a list round-trip
species + ("carpet",) # ("burmese", "rock", "ball", "blood", "carpet")
tuple(list(species) + ["carpet"]) # same result, via a list round-tripA tuple has no append() or remove() — but + builds a new tuple with an item added (note the trailing comma in ("carpet",), needed to make it a one-item tuple rather than just parentheses around a string).
For bigger changes, convert to a list with list(), edit it normally, then convert back with tuple().
species = ("burmese", "rock", "ball", "blood")
combined = species + ("carpet",)
print(combined)
as_list = list(species)
as_list.append("carpet")
back_to_tuple = tuple(as_list)
print(back_to_tuple)
Loop Tuples
for s in species: print(s) # burmese rock ball blood
for s in species: print(s) # burmese rock ball bloodLooping over a tuple works exactly like looping over a list.
species = ("burmese", "rock", "ball", "blood")
for s in species:
print(s)
Dictionaries
A dictionary stores data as key-value pairs, inside a single variable.
Dictionaries have three defining traits:
- Ordered — items keep the order they were inserted in.
- Changeable (mutable) — you can add, remove, or change items after the dictionary is created.
- No duplicate keys — a key can only appear once; assigning to an existing key overwrites its value.
snake = {
"species": "ball",
"length_ft": 5,
"venomous": False
}
print(snake)
Access Items
snake["species"] # "ball"
snake.get("venomous") # False
snake.keys() # dict_keys(['species', 'length_ft', 'venomous'])
"species" in snake # True
snake["species"] # "ball"
snake.get("venomous") # False
snake.keys() # dict_keys(['species', 'length_ft', 'venomous'])
"species" in snake # TrueValues are accessed by key, in square brackets — unlike a list, there's no numeric position to use.
get() does the same thing, but returns None (or a default you choose) instead of raising an error if the key is missing.
keys(), values(), and items() return view objects over the dictionary's keys, values, or key-value pairs.
Use in to check whether a key exists at all.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
print(snake["species"])
print(snake.get("venomous"))
print(snake.keys())
print(snake.values())
print(snake.items())
print("species" in snake)
Change Items
snake["length_ft"] = 6 # {'species': 'ball', 'length_ft': 6, 'venomous': False}
snake.update({"venomous": False, "docile": True}) # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'docile': True}
snake["length_ft"] = 6 # {'species': 'ball', 'length_ft': 6, 'venomous': False}
snake.update({"venomous": False, "docile": True}) # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'docile': True}Assign to an existing key to change its value.
update() changes one or more keys at once — any key it doesn't recognize gets added instead.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
snake["length_ft"] = 6
print(snake)
snake = {"species": "ball", "length_ft": 5, "venomous": False}
snake.update({"venomous": False, "docile": True})
print(snake)
Add Items
snake["origin"] = "west africa" # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'origin': 'west africa'}
snake.update({"legless": True}) # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'legless': True}
snake["origin"] = "west africa" # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'origin': 'west africa'}
snake.update({"legless": True}) # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'legless': True}Assigning to a key that doesn't exist yet adds it.
update() adds a key too, if it isn't already there — the same method covers both adding and changing.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
snake["origin"] = "west africa"
print(snake)
snake = {"species": "ball", "length_ft": 5, "venomous": False}
snake.update({"legless": True})
print(snake)
Remove Items
snake.pop("venomous") # False (removed and returned)
snake.popitem() # ('venomous', False) — removes the last inserted pair
del snake["species"] # {'length_ft': 5, 'venomous': False}
snake.clear() # {}
snake.pop("venomous") # False (removed and returned)
snake.popitem() # ('venomous', False) — removes the last inserted pair
del snake["species"] # {'length_ft': 5, 'venomous': False}
snake.clear() # {}pop() removes a key and returns its value.
popitem() removes and returns the last inserted key-value pair, as a tuple.
del removes a key-value pair by key.
clear() empties the dictionary but keeps the (now empty) dictionary around.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
popped = snake.pop("venomous")
print(popped)
print(snake)
snake = {"species": "ball", "length_ft": 5, "venomous": False}
last = snake.popitem()
print(last)
print(snake)
snake = {"species": "ball", "length_ft": 5, "venomous": False}
del snake["species"]
print(snake)
snake = {"species": "ball", "length_ft": 5, "venomous": False}
snake.clear()
print(snake)
Loop Dictionaries
for key in snake: print(key) # species length_ft venomous
for value in snake.values(): print(value) # ball 5 False
for key, value in snake.items(): print(key, value) # species ball length_ft 5 venomous False
for key in snake: print(key) # species length_ft venomous
for value in snake.values(): print(value) # ball 5 False
for key, value in snake.items(): print(key, value) # species ball length_ft 5 venomous FalseLooping directly over a dictionary gives you its keys, one at a time.
Loop over .values() to get just the values instead.
Loop over .items() to get both the key and the value together.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
for key in snake:
print(key)
for value in snake.values():
print(value)
for key, value in snake.items():
print(key, value)
Copy Dictionaries
same_dict = snake # same_dict and snake are the same dictionary — mutating one mutates both
backup = snake.copy() # backup is a separate, independent dictionary
same_dict = snake # same_dict and snake are the same dictionary — mutating one mutates both
backup = snake.copy() # backup is a separate, independent dictionaryWriting new_dict = old_dict does not copy the dictionary — both speciess point to the same dictionary, so a change through either species shows up in both.
copy() (or dict()) makes a real, independent copy.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
same_dict = snake
same_dict["length_ft"] = 6
print(snake)
snake = {"species": "ball", "length_ft": 5, "venomous": False}
backup = snake.copy()
backup["length_ft"] = 6
print(snake)
print(backup)
Nested Dictionaries
snakes = {"ball": snake, "burmese": {"length_ft": 16, "venomous": False}}
snakes["burmese"]["length_ft"] # 16
snakes = {"ball": snake, "burmese": {"length_ft": 16, "venomous": False}}
snakes["burmese"]["length_ft"] # 16A dictionary's values can be other dictionaries — useful for grouping related records under one variable, like a whole collection of snakes keyed by species.
Chain square brackets to reach a value nested inside an inner dictionary.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
snakes = {
"ball": snake,
"burmese": {"length_ft": 16, "venomous": False},
}
print(snakes["burmese"]["length_ft"])
print(snakes["ball"]["species"])
Dictionary Exercises
Details & examples
Each box below is fully editable — write your answer, then click Run.
1. Add a key. Add a "docile" key set to True.
snake = {"species": "ball", "length_ft": 5}
# your code here
print(snake)
2. Remove a key. Remove "length_ft" from the dictionary.
snake = {"species": "ball", "length_ft": 5, "venomous": False}
# your code here
print(snake)
3. Loop and collect. Build a list of just the dictionary's keys, using a loop (not list(snake.keys())).
snake = {"species": "ball", "length_ft": 5, "venomous": False}
keys = []
# your code here
print(keys)
4. Nested access. Given the dictionary below, print the burmese python's length.
snakes = {
"ball": {"length_ft": 5, "venomous": False},
"burmese": {"length_ft": 16, "venomous": False},
}
# your code here
Show solutions
# 1. Add a key
snake = {"species": "ball", "length_ft": 5}
snake["docile"] = True
print(snake)
# 2. Remove a key
snake = {"species": "ball", "length_ft": 5, "venomous": False}
del snake["length_ft"]
print(snake)
# 3. Loop and collect
snake = {"species": "ball", "length_ft": 5, "venomous": False}
keys = []
for key in snake:
keys.append(key)
print(keys)
# 4. Nested access
snakes = {
"ball": {"length_ft": 5, "venomous": False},
"burmese": {"length_ft": 16, "venomous": False},
}
print(snakes["burmese"]["length_ft"])