GICT knowledge base
Python Lists, Tuples, Sets, and Dictionaries: Choosing a Collection
Published
Choose a Python collection according to how you need to access and change its data. A list holds a changing sequence, a tuple holds a fixed sequence, a set tracks unique members, and a dictionary maps keys to values. None of these types alone provides access control or makes shared data safe from every kind of modification.
Quick comparison
| Type | Access | Can it change? | Duplicate values | Typical use |
|---|---|---|---|---|
| list | Position or slice | Yes | Allowed | Ordered deployment steps |
| tuple | Position or slice | Item references cannot change | Allowed | Host-and-port record |
| set | Membership, not position | Yes | Equal members collapse | Unique service names |
| dict | Key | Yes | Keys unique; values may repeat | Service-to-status lookup |
Lists and tuples retain sequence order. Dictionaries preserve insertion order as a language guarantee from Python 3.7; CPython 3.6 already did so as an implementation detail. Sets do not promise an iteration order. Sorting a set produces a separate list.
List: keep a sequence you will edit
steps = ["backup", "deploy"]
steps.append("verify")
steps.insert(1, "maintenance")
assert steps == ["backup", "maintenance", "deploy", "verify"]
assert steps[0] == "backup"
assert steps[-1] == "verify"
removed = steps.pop(1)
assert removed == "maintenance"
append() adds one object; extend() adds the items from an iterable. In-place methods such as append() do not return the updated list, so do not assign their result back to the list variable. Use remove(value) to remove the first equal value; it raises ValueError when absent.
Tuple: hold a fixed record
endpoint = ("web.example", 443)
host, port = endpoint
assert host == "web.example"
assert port == 443
assert (443,) != 443
try:
endpoint[1] = 8443
except TypeError:
print("Cannot replace a tuple item")
A tuple containing a list still permits the list itself to change. For detailed examples, see Python Tuple Basics. Do not select tuples solely because of a blanket claim that all tuple operations are faster.
Set: compare unique members
expected = {"nginx", "php-fpm"}
observed = {"nginx", "redis", "nginx"}
missing = expected - observed
unexpected = observed - expected
shared = expected & observed
assert missing == {"php-fpm"}
assert unexpected == {"redis"}
assert shared == {"nginx"}
assert sorted(expected | observed) == ["nginx", "php-fpm", "redis"]
This is a comparison of sample strings, not a command that checks running services. Create an empty set with set(); {} creates a dictionary. Use discard(value) if an absent value should be ignored, or remove(value) if absence should raise KeyError. Set membership is based on hashing and equality, so {1, True} has one member because those values compare equal.
Dictionary: look up a value by key
status = {"nginx": "running", "redis": "stopped"}
assert status["nginx"] == "running"
assert status.get("php-fpm", "unknown") == "unknown"
keys = status.keys()
status["php-fpm"] = "running"
assert "php-fpm" in keys
assert list(status) == ["nginx", "redis", "php-fpm"]
for name, state in status.items():
print(name, state)
keys(), values(), and items() return views, not lists. The example’s existing keys view reflects the newly added key. Use list(status.keys()) when you specifically need a list snapshot. Direct access to a missing key raises KeyError; get() can return a default. Assigning an existing key replaces its value without creating another equal key.
Hashable is the key requirement
Dictionary keys and set members must be hashable. Strings and integers work. Lists, dictionaries, and ordinary sets do not. A tuple is hashable only when each item is hashable. This is more precise than saying that every immutable object is an acceptable key.
checks = {("web.example", 443): "pending"}
assert checks[("web.example", 443)] == "pending"
try:
hash(("web.example", [443]))
except TypeError:
print("The nested list is not hashable")
See hashability and the Python data-structures tutorial for the formal behavior.
Watch for shallow copies
original = [["nginx"]]
copied = original.copy()
copied[0].append("redis")
assert original == [["nginx", "redis"]]
assert copied is not original
assert copied[0] is original[0]
The outer list was copied, but both lists refer to the same inner list. A change to that inner object is visible through both. Decide whether you need independent nested objects before copying configuration or task data; a new outer container alone is not enough.
Verification: All six code blocks were executed with Python 3.12.14. The assertions check order, views, set comparisons, expected type errors, and shared references. These are correctness examples, not performance benchmarks.
Related guides
How to Deploy a FastAPI App with Gunicorn and Nginx
Deploy FastAPI behind Nginx with Gunicorn and systemd. Separate application packages, check HTTPS and verify worker replacement and application health.
PythonLearn How to Modify Python Dictionary Values Easily
Learn how to modify Python dictionary values effectively with various methods, including direct assignment, update(), and comprehensions, along with common mistakes to...
PythonPython Set Copy Tutorial: Avoid Common Mistakes and Data Errors
Learn how to copy sets in Python safely and efficiently while avoiding common mistakes. Explore methods like copy(), set(), and deepcopy().
PythonDifferent Methods to Loop Through Sets in Python (Beginner-Friendly Guide)
Learn diverse methods to loop through sets in Python, including practical examples and use cases, ideal for beginners looking to master set operations.
