Collection Data Types
A collection is a single object that groups multiple values (like basic types) together and so they can be stored in one variable together and worked with as a unit.
| Collection Type | Example | Access values by | Use it for |
|---|---|---|---|
list |
|
position # |
|
dictionary "dict" |
|
Name of a key |
|
tuple |
|
position # |
|
set |
|
Membership (in) |
|
Check what type a variable is
type() shows the data type
isinstance() checks whether a value is that type.
weights = [5, 3, 6]
type(weights) # <class 'list'>
isinstance(5, list) # True
isinstance(5, dict) # False
Lists
Create a list
-
A list stores multiple items, in order, inside a single variable. The items can be any type.
species = ["burmese", "rock", "ball", "blood"]
The index is the numbered position of an item. The index of the first item is 01, next is 1, and so on.
block-beta
block:diagram
columns 5
lblValue["Value"] v0[""burmese""] v1[""rock""] v2[""ball""] v3[""blood""]
lblIndex["Index"] i0["0"] i1["1"] i2["2"] i3["3"]
lblNeg["Negative index"] n0["-4"] n1["-3"] n2["-2"] n3["-1"]
end
classDef label fill:none,stroke:none,color:#8A8370
classDef panel fill:#23221E,stroke:#35342E,stroke-width:1px
class i0,i1,i2,i3,n0,n1,n2,n3,lblValue,lblIndex,lblNeg label
class diagram panel
Fig. 5a — list values with their positive and negative indexes
- The negative index tells you how far from the end it is. It starts counting down from the end instead, starting at
-1for the last item, -2 for the second-to-last, and so on. Each item can be referenced by its positive or negative index.
Access and update items
-
Index with
list[index]to return the item at that index (position number) of the list.To update the item at that index, set it equal to something else
list[index] = new_item.Run the below example, and change the indexes to see how they work:
species = ["burmese", "rock", "ball", "blood"] print(species) print(species[0]) # "burmese" print(species[1]) # "rock" print(species[-1]) # "blood" species[1] = "carpet" # ["burmese", "carpet", "ball", "blood"] print(species) -
Acccess a range of multiple items at once:
-
Slice with
list[start:end]to return a new list containing items from thestartindex up to (but not including) theendindex.species[1:3] # ["rock", "ball"], starts at index 1, stops at (doesn't include) index 3 -
Step with
list[start:end:step]to return a new list that can skip items instead of taking every one —start/endare optional so if you leave them off the step is applied to the whole list. A step of-1walks backward, which is the standard trick for reversing a list. You can also add a start and end range just like a slice.species[::2] # ["burmese", "ball"] — every 2nd item species[::-1] # ["blood", "ball", "rock", "burmese"] — reversed
Assigning to a range
Setting a slice or step
=equal to a list will replaces that whole range at once with the new list.A plain slice accepts a replacement of any length — it doesn't need to match the range being replaced.
species[1:3] = ["carpet", "rock"] # ["burmese", "carpet", "rock", "blood"]A step, on the other hand, requires the replacement to supply exactly as many items as the step selected, or Python raises a
ValueError.species[::2] = ["carpet", "anaconda"] # ["carpet", "rock", "anaconda", "blood"] -
Loop through a list
-
Lists make it simple to loop directly over the items. The loop runs once for every item in the list, and on each pass the new loop variable, (i.e.
specie) is set to the next item in the list.for specie in species: print(specie) # specie is "burmese", then "rock", then "ball", then "blood" — one item per pass -
If you also want the index of the item alongside the item itself,
enumerate()hands back both together.for index, specie in enumerate(species): print(index, specie) # 0 "burmese", then 1 "rock", then 2 "ball", then 3 "blood"
Boolean expressions
-
in,not inchecks whether a value exists or is missing in the list."burmese" in species # True "anaconda" not in species # True -
==,!=checks whether a specific item is equal or not equal to something.species[0] == "burmese" # True species[0] != "blood" # TrueWhen comparing whole lists, it will say if the two lists have the same contents, in the same order.
other_species = ["burmese", "rock", "ball", "blood"] species == other_species # True species != ["ball", "burmese"] # True -
is,is notchecks whether two variables point to the exact same list object, not just an equal one.same_species = species # another name for the same list copy_of_species = species[:] # a separate list, equal contents species is same_species # True, same list species is copy_of_species # False, different list with equal contents -
is list emptytruthiness (boolean value of the whole list)-
Truthy: a list with contents
-
Falsy: an empty list
[]
if species: # runs if the list has items print("found some") while species: # loops until the list is empty species.pop() -
List operations
Inspect
-
len()returns how many items are in a list.len(species) # 4 -
index()finds the position of the first match.species.index("burmese") # 0 -
count()counts how many times a value appears.species.count("ball") # 1
Add item
-
append()adds one item to the end of the list.species.append("carpet") # ["burmese", "rock", "ball", "blood", "carpet"] -
insert()adds an item at a specific index, without overwriting what's already there.species.insert(1, "carpet") # ["burmese", "carpet", "rock", "ball", "blood"] -
extend()adds every item from another iterable.species.extend(["carpet", "central african rock"]) # ["burmese", "rock", "ball", "blood", "carpet", "central african rock"]
Remove item
-
remove()deletes the first item that matches a given value. If there are duplicate items, it only removes the first one.species.remove("rock") # ["burmese", "ball", "blood"] -
pop()deletes an item by index and returns it — with no index, it removes the last item.species.pop() # "blood" (removed and returned last item) species.pop(0) # "burmese" (removed and returned item at index 0) -
delremoves an item by index, or can delete the entire list.del species[0] # ["rock", "ball", "blood"] del species # deletes the whole list — species no longer exists -
clear()empties the list but keeps the (now empty) list around.species.clear() # []
Sort
-
sort()sorts the list in place, alphabetically (or ascending, for numbers) by default. Passreverse=Trueto sort in the opposite order, or akeyfunction to control what each item is sorted by.species.sort() # ["ball", "blood", "burmese", "rock"] species.sort(reverse=True) # ["rock", "burmese", "blood", "ball"] species.sort(key=len) # ["rock", "ball", "blood", "burmese"] -
sorted()does the same job assort(), but returns a new list, leaving the original untouched.sorted(species) # same as sort() above, but returns a new list -
reverse()flips the current order in place — different fromsort(reverse=True), since it doesn't actually sort, just reverses.species.reverse() # ["blood", "ball", "rock", "burmese"]
Arithmetic
-
min()finds the smallest item.min(length_ft) # 3.5 -
max()finds the largest item.max(length_ft) # 12 -
sum()adds every item together.sum(length_ft) # 25
Create
-
list()builds the same list from any iterable, if you'd rather not use literal brackets.list(("burmese", "rock", "ball", "blood")) # ["burmese", "rock", "ball", "blood"] -
+joins two lists into a new one.species + ["carpet", "boa"] # ["burmese", "rock", "ball", "blood", "carpet", "boa"] -
copy()makes a real, independent copy of the list — unlikenew_list = old_list, which just points a second name at the same list, so a change through either name shows up in both.same_list = species # same_list and species are the same list — changing one changes both backup = species.copy() # backup is a separate, independent list
List comprehension
-
[expr for item in iterable]builds a new list from an existing iterable in a single line. The expression part can transform each item, not just filter it.[s for s in species if len(s) > 4] # ["burmese", "blood"] [s.title() for s in species] # ["Burmese", "Rock", "Ball", "Blood"]
Going further
Practice with lists
Each box below is fully editable — write your answer, then click Run.
1. Access & check membership. Print the second item in the list (index 1), then check whether "rock" is in it.
species = ["indian", "carpet", "rock", "angolan", "blood"]
# your code here
2. Change & add. Change the first item to "burmese", then add "bornean" to the end.
species = ["indian", "carpet", "rock", "angolan", "blood"]
# your code here
print(species)
3. Remove. Remove "carpet" from the list, then pop the last item and print what was removed.
species = ["indian", "carpet", "rock", "angolan", "blood"]
# your code here
4. List comprehension. Build a list of just the names with more than 5 letters.
species = ["indian", "carpet", "rock", "angolan", "blood"]
# your code here
print(long_names)
5. Sort. Sort the list in reverse alphabetical order.
species = ["indian", "carpet", "rock", "angolan", "blood"]
# your code here
print(species)
Show solutions
# 1. Access & check membership
species = ["indian", "carpet", "rock", "angolan", "blood"]
print(species[1])
print("rock" in species)
# 2. Change & add
species = ["indian", "carpet", "rock", "angolan", "blood"]
species[0] = "burmese"
species.append("bornean")
print(species)
# 3. Remove
species = ["indian", "carpet", "rock", "angolan", "blood"]
species.remove("carpet")
last = species.pop()
print(last)
# 4. List comprehension
species = ["indian", "carpet", "rock", "angolan", "blood"]
long_names = [s for s in species if len(s) > 5]
print(long_names)
# 5. Sort
species = ["indian", "carpet", "rock", "angolan", "blood"]
species.sort(reverse=True)
print(species)
Extending lists with collections.deque
A list can already add or remove items from the end cheaply, but doing the same at the
front — species.insert(0, item) or species.pop(0) — means Python has to shift every
other item over. The collections library's
deque adds fast appendleft()/popleft() methods for
exactly that case. Switch to it when items are being added or removed from both ends
often, like a queue of items processed in the order they arrive — not for a list that's
mostly read or only changed at the end, where a plain list is simpler and already fast.
See the collections library page for the rest of deque's
methods (rotate(), maxlen=, and more) and for the other list-adjacent tools it adds.
Dictionaries
Create a dictionary
-
A dictionary stores data as key-value pairs, inside a single variable. Values are looked up by key, not by a numbered position like a list's index — a dict does remember the order keys were added in, but that order isn't how you access anything.
snake = { "species": "ball", "length_ft": 5, "venomous": False }
%%{init: {"flowchart": {"nodeSpacing": 15}}}%%
flowchart LR
subgraph snake["snake"]
direction LR
lblKey["`*Key*`"] ~~~ lblVal["`*Value*`"]
key1["species"] --> val1["'ball'"]
key2["length_ft"] --> val2["5"]
key3["venomous"] --> val3["False"]
end
style key1 stroke:#3f6b52,stroke-width:2px
style key2 stroke:#3f6b52,stroke-width:2px
style key3 stroke:#3f6b52,stroke-width:2px
style lblKey fill:none,stroke:none,color:#8A8370
style lblVal fill:none,stroke:none,color:#8A8370
Fig. 5b — a dict's key-value pairs
- Each **key** points to exactly one value.
- **A key's type** can be a string, int, float, or tuple
- **No duplicate keys** — assigning a value to an existing key overwrites its value.
- A **value** can be any type.
Access a value
-
dict[key]accesses a value by key, in square brackets. This will raise an error if the key is not present, so best practice is to use the below get() instead.snake["species"] # "ball" -
get()does the same thing, but returnsNoneif the key is not in the dict. You can provide an optinal default value to fall back on that will be returned if they key is not in the dict.snake.get("species") # "ball" snake.get("weight_lbs", 0) # 0 — key is missing, so the default is returned instead of None
Loop through a dictionary
-
Looping directly over a dictionary gives you its keys, one at a time — the loop runs once for every key in the dictionary, and on each pass the loop variable, (i.e.
key) is set to the next key.for key in snake: print(key) # species length_ft venomous -
Loop over
.values()to get just the values instead.for value in snake.values(): print(value) # ball 5 False -
Loop over
.items()to get both the key and the value together.for key, value in snake.items(): print(key, value) # species ball length_ft 5 venomous False
Boolean expressions
-
inchecks whether a key exists at all."species" in snake # True -
not inchecks whether a key is missing. Or compare a specific value directly, likesnake["length_ft"] > 2."habitat" not in snake # True -
==checks whether two dictionaries have the same keys and values, even if they're different objects.!=checks whether they differ.other_snake = {"species": "ball", "length_ft": 5, "venomous": False} snake == other_snake # True -
ischecks whether two variables point to the exact same dictionary object, not just an equal one — use==to compare contents.same_snake = snake # another name for the same dictionary copy_of_snake = snake.copy() # a separate dictionary, equal contents snake is same_snake # True, same dictionary snake is copy_of_snake # False, different dictionary with equal contents -
boolean expression:
-
Truthy: a dictionary with at least one key
-
Falsy: an empty dictionary
{}
if snake: # runs if dictionary is not empty print("found a record") while snake: # loops until the dictionary is empty snake.popitem() -
Dictionary operations
Inspect
-
len()returns how many key-value pairs are in a dictionary.len(snake) # 3
Update
-
dict[key] = valuesets a key's value — changes it if the key already exists, adds it if not.snake["length_ft"] = 6 # {'species': 'ball', 'length_ft': 6, 'venomous': False} snake["origin"] = "west africa" # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'origin': 'west africa'} -
update()does the same for multiple keys at once — changes any that already exist, and adds any that don't.snake.update({"venomous": False, "docile": True}) # {'species': 'ball', 'length_ft': 5, 'venomous': False, 'docile': True}
Remove
-
pop()removes a key and returns its value.snake.pop("venomous") # False (removed and returned) -
popitem()removes and returns the last inserted key-value pair, as a tuple.snake.popitem() # ('venomous', False) — removes the last inserted pair -
delremoves a key-value pair by key.del snake["species"] # {'length_ft': 5, 'venomous': False} -
clear()empties the dictionary but keeps the (now empty) dictionary around.snake.clear() # {}
Create
-
dict()builds the same dictionary using keyword arguments, if you'd rather not use literal braces.dict(species="ball", length_ft=5, venomous=False) # {'species': 'ball', 'length_ft': 5, 'venomous': False} -
copy()makes a real, independent copy of the dictionary — unlikenew_dict = old_dict, which just points a second name at the same dictionary, so a change to either would effect both.same_dict = snake # same_dict and snake are the same dictionary — mutating one mutates both backup = snake.copy() # backup is a separate, independent dictionary
Nested dictionaries
A 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 operations one after the other to reach a value nested inside an inner dictionary.
snakes = {
"ball": snake,
"burmese": {
"length_ft": 16,
"venomous": False
}
}
snakes["burmese"]["length_ft"] # 16
Going further
Practice with dictionaries
Each box below is fully editable — write your answer, then click Run.
1. Add & change. Add a "docile" key set to True, then change "length_ft" to 16.
snake = {"species": "burmese", "length_ft": 12, "venomous": False}
# your code here
print(snake)
2. Remove. Remove the "venomous" key from the dictionary.
snake = {"species": "burmese", "length_ft": 16, "venomous": False}
# your code here
print(snake)
3. Loop and collect. Build a list of just the dictionary's values, using a loop (not list(snake.values())).
snake = {"species": "burmese", "length_ft": 16, "venomous": False}
values = []
# your code here
print(values)
4. Nested access. Given the dictionary below, print the ball python's length.
snakes = {
"burmese": {"length_ft": 16, "venomous": False},
"ball": {"length_ft": 5, "venomous": False},
}
# your code here
Show solutions
# 1. Add & change
snake = {"species": "burmese", "length_ft": 12, "venomous": False}
snake["docile"] = True
snake["length_ft"] = 16
print(snake)
# 2. Remove
snake = {"species": "burmese", "length_ft": 16, "venomous": False}
del snake["venomous"]
print(snake)
# 3. Loop and collect
snake = {"species": "burmese", "length_ft": 16, "venomous": False}
values = []
for value in snake.values():
values.append(value)
print(values)
# 4. Nested access
snakes = {
"burmese": {"length_ft": 16, "venomous": False},
"ball": {"length_ft": 5, "venomous": False},
}
print(snakes["ball"]["length_ft"])
Extending dicts with collections
A plain dict can tally counts or group items, but both take extra setup code: checking
whether a key exists before incrementing it, or before appending to a list under it. The
collections library adds several dicts that handle cases
like these automatically.
Countercounts items in a sequence directly — reach for it as soon as a dict's job is "how many times does each item show up."defaultdictsupplies an empty value (a list, a set,0) the first time a new key is used, so grouping items under keys that aren't known ahead of time doesn't need anif key not in dictcheck before every write.OrderedDictis worth reaching for only when order itself needs to be compared or reordered — a plain dict already remembers insertion order, but its==ignores that order, and it has nomove_to_end().ChainMaplayers several dicts together — like a set of overrides checked before a set of defaults — without copying or merging them into a new dict.
See the collections library page for the full method list on each of these.
Tuples
A tuple stores multiple items, in order, written in parentheses. They are immutable so the items can't be changed once its created.
species = ("burmese", "rock", "ball", "blood")
block-beta
block:diagram
columns 5
lblValue["Value"] v0[""burmese""] v1[""rock""] v2[""ball""] v3[""blood""]
lblIndex["Index"] i0["0"] i1["1"] i2["2"] i3["3"]
lblNeg["Negative index"] n0["-4"] n1["-3"] n2["-2"] n3["-1"]
end
classDef label fill:none,stroke:none,color:#8A8370
classDef panel fill:#23221E,stroke:#35342E,stroke-width:1px
class i0,i1,i2,i3,n0,n1,n2,n3,lblValue,lblIndex,lblNeg label
class diagram panel
Fig. 5c — tuple values with their positive and negative indexes
The index of the first item is 01, next is 1, and so on.
The negative index starts counting down from the end instead, starting at -1 for the last item, -2 for the second-to-last, and so on. Each item can be referenced by its positive or negative index.
Access items
-
Index with
tuple[index].species[0] # "burmese" species[-1] # "blood" -
A slice
tuple[start:end]returns a new tuple containing items fromstartindex up to (but not including) theendindex.species[1:3] # ("rock", "ball")
Loop through a tuple
-
The loop runs once for every item in the tuple, and on each pass the loop variable, (i.e.
specie) is set to the next item in the tuple.for specie in species: print(specie) # burmese rock ball blood -
If you also want the index alongside the item,
enumerate()hands back both together — works the same as on a list, since tuples support indexing too.for index, specie in enumerate(species): print(index, specie) # 0 "burmese", then 1 "rock", then 2 "ball", then 3 "blood"
Boolean expressions
-
inchecks whether a value exists in the tuple."rock" in species # True -
not inchecks whether a value is missing from the tuple."carpet" not in species # True -
==checks whether two tuples have the same contents, in the same order.!=checks whether they differ. Or compare a specific item directly, likespecies[0] == "burmese".other_species = ("burmese", "rock", "ball", "blood") species == other_species # True species != ("burmese",) # True -
ischecks whether two variables point to the exact same tuple object, not just an equal one — use==to compare contents.same_species = species # another name for the same tuple species is same_species # True, same tuple species is ("burmese", "rock", "ball", "blood") # False, different tuple with equal contents -
boolean expression:
-
Truthy: a tuple with contents
-
Falsy: an empty tuple
()
if species: # runs — species tuple has items print("found some") -
Packing and unpacking
-
Packing: writing several values separated by commas, with or without the surrounding parentheses, implicitly builds a tuple.
species = "burmese", "rock", "ball", "blood" # parentheses optional — still a tuple type(species) # <class 'tuple'> -
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.
a, b, c, d = species # a="burmese" b="rock" c="ball" d="blood"A
matchstatement can do this same unpacking while also branching on the tuple's shape or specific values.snake = (12, "ball") match snake: case (length, "ball"): # tuple with 2 items, where second is "ball" print(f"a {length} ft ball python") # in this example, this case will run case (length, specie): # tuple with any 2 items print(f"a {length} ft {specie} python") case (length,): # tuple with any 1 item print(f"just a length: {length}") case _: # 0 items, or tuple with more than 2 items print("invalid format")
Tuple operations
Inspect
-
len()returns how many items are in a tuple.len(species) # 4 -
count()counts how many times a value appears.species.count("burmese") # 1 -
index()finds the position of the first match.species.index("ball") # 2
Arithmetic
-
min()finds the smallest item.length_ft = (12, 4.5, 3.5, 5) min(length_ft) # 3.5 -
max()finds the largest item.max(length_ft) # 12 -
sum()adds every item together.sum(length_ft) # 25
Convert to modify
-
Convert to list -> edit -> convert back to tuple builds a new tuple since a tuple can't be edited directly.
species_list = list(species) # convert tuple to a list species_list.append("carpet") # edit it like any list species = tuple(species_list) # convert back to tuple and reassign
Create
-
tuple()builds the same tuple from any iterable, if you'd rather not use literal parentheses.tuple(["burmese", "rock", "ball", "blood"]) # ("burmese", "rock", "ball", "blood")
Going further
Practice with tuples
Each box below is fully editable — write your answer, then click Run.
1. Access & check membership. Print the last item, then check whether "carpet" is in the tuple.
species = ("indian", "carpet", "rock", "blood")
# your code here
2. Unpacking. Unpack the tuple into four variables named a, b, c, d, then print them.
species = ("indian", "carpet", "rock", "blood")
# your code here
3. Work around immutability. Tuples can't be appended to directly — build a new tuple with "angolan" added to the end, using +.
species = ("indian", "carpet", "rock", "blood")
# your code here
print(species)
Show solutions
# 1. Access & check membership
species = ("indian", "carpet", "rock", "blood")
print(species[-1])
print("carpet" in species)
# 2. Unpacking
species = ("indian", "carpet", "rock", "blood")
a, b, c, d = species
print(a, b, c, d)
# 3. Work around immutability
species = ("indian", "carpet", "rock", "blood")
species = species + ("angolan",)
print(species)
Extending tuples with collections.namedtuple
A plain tuple's items can only be accessed by position — snake[1] doesn't say what
that value actually means without checking back how the tuple was built. The
collections library's
namedtuple builds a tuple type with named fields,
so the same value reads as snake.length_ft. Switch to it once a tuple's positions start
needing a mental lookup table to remember, or once several tuples share the same shape
throughout a program — a single namedtuple definition documents that shape once instead
of repeating a comment at every literal.
See the collections library page for namedtuple's other
methods (_asdict(), _replace(), default field values) and the rest of the module.
Sets
A set stores multiple items, in no particular order, inside a single variable — written with curly braces.
Because items have no fixed position, there's no indexing. Duplicates are irrelevant because adding a value that's already there changes nothing; a set can only ever hold each value once.
species = {"burmese", "rock", "ball", "blood"} # order not fixed
block-beta
block:diagram
columns 5
lblValue["Unordered set: "] v0[""burmese""] v1[""rock""] v2[""ball""] v3[""blood""]
end
classDef label fill:none,stroke:none,color:#8A8370
classDef panel fill:#23221E,stroke:#35342E,stroke-width:1px
class lblValue label
class diagram panel
Fig. 5d — set values with no fixed order
Loop through a set
The loop runs once for every item in the set, in no guaranteed order, and on each pass the loop variable, (i.e. specie) is set to the next item.
for specie in species:
print(specie) # burmese rock ball blood — order not guaranteed
Boolean expressions
-
inchecks whether a value exists — and does it far faster than a list or tuple, no matter how large the set gets, since Python looks it up directly instead of scanning item by item."burmese" in species # True -
not inchecks whether a value is missing from the set."cobra" not in species # True -
==checks whether two sets have the same contents, regardless of order.!=checks whether they differ.other_species = {"burmese", "rock", "ball", "blood"} species == other_species # True -
ischecks whether two variables point to the exact same set object, not just an equal one — use==to compare contents.same_species = species # another name for the same set copy_of_species = species.copy() # a separate set, equal contents species is same_species # True, same set species is copy_of_species # False, different set with equal contents -
issubset(),issuperset(),isdisjoint()compare two sets and hand back abooltoo — see Set operations: Compare for the full rundown. -
boolean expression:
-
Truthy: a set with contents
-
Falsy: an empty set — written
set(), not{}, since{}creates an empty dict instead
if species: # runs — the set has items print("found some") while species: # loops until the set is empty species.pop() -
Set operations
Inspect
-
len()returns how many items are in a set.len(species) # 4
Arithmetic
-
min()finds the smallest item.length_ft = {12, 4.5, 3.5, 5} min(length_ft) # 3.5 -
max()finds the largest item.max(length_ft) # 12 -
sum()adds every item together.sum(length_ft) # 25
Update
-
add()adds a single item. Adding a value that's already present changes nothing.species.add("carpet") # {"burmese", "rock", "ball", "blood", "carpet"} species.add("burmese") # already there — no change -
update()adds every item from another iterable, one at a time.species.update(["carpet", "boa"]) # adds "boa"; "carpet" was already there
Remove
-
remove()deletes an item, raising an error if it isn't there.species.remove("rock") # errors if "rock" isn't in the set -
discard()does the same but stays silent if the item's missing.species.discard("rock") # no error either way -
pop()removes and returns an arbitrary item, since there's no "last" item in an unordered collection.species.pop() # removes and returns *some* item — which one isn't guaranteed -
clear()empties the set.species.clear() # set()
Combine
Sets support the same operations as sets in math class — useful for comparing two groups directly instead of writing your own loop to do it.
constrictors = {"ball", "burmese", "boa"}
pet_friendly = {"ball", "burmese", "corn snake"}
-
|union — everything in either set.constrictors | pet_friendly # {"ball", "burmese", "boa", "corn snake"} -
&intersection — only what's in both.constrictors & pet_friendly # {"ball", "burmese"} -
-difference — in the first set, but not the second.constrictors - pet_friendly # {"boa"} -
^symmetric difference — in one set or the other, but not both.constrictors ^ pet_friendly # {"boa", "corn snake"}
Compare
These check a relationship between two sets and hand back a bool, rather than building a new set the way Combine does.
-
issubset()checks whether every item in this set is also in another set.{"ball", "burmese"}.issubset(constrictors) # True -
issuperset()checks whether this set contains every item in another set — the reverse ofissubset().constrictors.issuperset({"ball"}) # True -
isdisjoint()checks whether two sets have no items in common.constrictors.isdisjoint({"cobra", "viper"}) # True
Create
-
set()builds the same set from any iterable, if you'd rather not use literal braces.set(["burmese", "rock", "ball", "blood"]) # {'burmese', 'rock', 'ball', 'blood'} -
copy()makes a real, independent copy of the set — unlikenew_set = old_set, which just points a second name at the same set, so a change through either name shows up in both.same_set = species # same_set and species are the same set — mutating one mutates both backup = species.copy() # backup is a separate, independent set
Removing duplicates from a list
Converting a list to a set and back is a common one-line way to drop duplicates — though it also throws away the original order, unless you sort or otherwise re-derive it.
species = ["ball", "burmese", "ball", "boa", "burmese"]
list(set(species)) # ["burmese", "ball", "boa"] — order not guaranteed
Going further
Practice with sets
Each box below is fully editable — write your answer, then click Run.
1. Check membership & add. Check whether "carpet" is in the set, then add it.
species = {"indian", "rock", "blood", "angolan"}
# your code here
2. Remove. Discard "rock" from the set — using the method that won't error even if it's already gone.
species = {"indian", "rock", "blood", "angolan"}
# your code here
print(species)
3. Deduplicate. Given the list below (with repeats), build a set from it to remove duplicates, then convert it back to a list.
names = ["ball", "burmese", "ball", "boa", "burmese"]
# your code here
print(unique_names)
Show solutions
# 1. Check membership & add
species = {"indian", "rock", "blood", "angolan"}
print("carpet" in species)
species.add("carpet")
# 2. Remove
species = {"indian", "rock", "blood", "angolan"}
species.discard("rock")
print(species)
# 3. Deduplicate
names = ["ball", "burmese", "ball", "boa", "burmese"]
unique_names = list(set(names))
print(unique_names)
-
In programming, counting generally starts at 0, not 1. That's because an index isn't really a count of "how manyth" item something is — it's an offset, the number of steps from the start. The first item is 0 steps away, so it gets index
0. It feels different from counting out loud ("first, second, third..."), but it's the convention nearly every programming language follows. ↩↩