Innovate | Connect | Transform
ContactService statusUSD $

GICT knowledge base

Python Lists, Tuples, Sets, and Dictionaries: Choosing a Collection

Published

Python

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

Account services are unavailable until the production backend is configured.