Collections

Most game data is a collection of values rather than a single value. Python gives you three core built-in collection types, each suited to different situations.

Lists

A list is an ordered, mutable sequence of values. The elements do not have to be the same type. Create one with square brackets:

inventory = ["sword", "shield", "health_potion"]
enemies_in_room = []     # empty list, filled during level load
mixed = ["goblin", 3, True, 9.5]

Access elements by index (zero-based). Negative indices count from the end:

first_item = inventory[0]    # "sword"
last_item  = inventory[-1]   # "health_potion"

Lists are mutable — you can change an element after creation:

inventory[1] = "tower_shield"   # upgrade the shield

Add and remove elements:

inventory.append("magic_wand")     # add to end
inventory.remove("health_potion")  # remove first occurrence

sort() sorts the list in place. len() returns the number of elements. The in operator checks membership:

if "shield" in inventory:
    armor_bonus = 10

Iterating a list with a for loop:

for enemy in enemies_in_room:
    enemy.update()

If you need to modify elements by index while iterating, combine range and len:

for i in range(len(enemies_in_room)):
    enemies_in_room[i].health -= splash_damage

List operations — + concatenates two lists; * repeats:

wave1 = ["goblin", "goblin"]
wave2 = ["orc"]
full_wave = wave1 + wave2     # ["goblin", "goblin", "orc"]
patrol = ["guard"] * 4        # ["guard", "guard", "guard", "guard"]

Dictionaries

A dictionary maps keys to values — you look up a value by name rather than by position. Each key–value pair is called an item:

keybindings = {
    "move_forward":  "w",
    "move_backward": "s",
    "jump":          "space",
    "attack":        "mouse1",
}

player_stats = {
    "health":  100,
    "mana":    50,
    "stamina": 75,
}

Access by key — raises KeyError if the key is missing:

jump_key       = keybindings["jump"]
current_health = player_stats["health"]

Safe access with a default (no error if the key is absent):

gold = player_stats.get("gold", 0)   # returns 0 if "gold" not set

Update a value:

player_stats["health"] -= 20   # take 20 damage

Check whether a key exists with in (note: in checks keys, not values):

if "shield" in equipped_items:
    armor_bonus += 10

Iterate over all items:

for action, key in keybindings.items():
    print(f"{action}: {key}")

The in operator on a dictionary uses a hash table internally, meaning the lookup takes the same amount of time whether the dictionary has 10 items or 10,000. This makes dictionaries the right choice whenever you need fast lookups by name — ability lookup tables, asset registries, event dispatch tables.

Tuples

A tuple is like a list but immutable — its contents cannot change after creation. This makes tuples appropriate for values that belong together and should never be modified: a fixed coordinate, a color, a key binding pair.

spawn_point  = (32.0, 0.0, 5.0)    # (x, y, z)
RED          = (1.0, 0.0, 0.0, 1.0)  # RGBA color

Tuples support indexing and slicing just like lists:

x = spawn_point[0]
print(spawn_point[1:3])   # (0.0, 5.0)

But you cannot modify an element:

spawn_point[0] = 99.0   # TypeError: object doesn't support item assignment

Tuple unpacking assigns each element to a named variable in one step:

x, y, z = spawn_point

Tuples are also hashable, which means they can be used as dictionary keys. A list cannot be a dictionary key; a tuple can. This is useful for grid-based games where you want to look up a cell by its (row, col) position:

tile_data = {
    (0, 0): "grass",
    (0, 1): "water",
    (1, 0): "stone",
}
cell_type = tile_data[(row, col)]