The problem: Module 1 used individual values, but real applications need groups: thousands of documents, a sequence of tokens, or a conversation full of messages. Creating
document1,document2, and hundreds of other variable names would be impossible to manage.What you will learn: Collections let Python hold many related values as one organized object. You will compare lists, tuples, sets, and dictionaries, then choose among them based on order, changeability, uniqueness, and key-based lookup.
1. Lists
First picture the difference between one value and a collection:
one document → "Python is readable."
many documents → [document 0, document 1, document 2]
↑ ↑ ↑
position position position
The brackets create one list object that can be passed to a function, looped over, or returned from an API-processing step. The values do not have to be text, although grouping related kinds of values usually makes code clearer.
What a List Stores
A list is an ordered, changeable collection of values.
tokens = ["The", "capital", "of", "France", "is", "Paris"]
Why One Variable Is Better Than Hundreds
Without lists, you’d need a separate variable for every single item —
token1, token2, token3… completely unworkable once you have
hundreds or thousands of items.
Picture It as Numbered Boxes
A list is a numbered row of boxes, all bundled under one name. You can add boxes, remove boxes, or look inside any box by its position.
A Familiar Example
Think of a list as a shopping list on paper — items in order, and you can add an item, cross one out, or check what’s at position 3.
Syntax
my_list = [item1, item2, item3]
Example
# Storing retrieved documents for a RAG pipeline
documents = [
"Paris is the capital of France.",
"The Eiffel Tower is located in Paris.",
"France is a country in Western Europe."
]
# Adding a newly retrieved document
documents.append("The Louvre is the world's most visited museum.")
# Removing a document
documents.remove("France is a country in Western Europe.")
print(documents)
print(len(documents))
Expected Output:
['Paris is the capital of France.', 'The Eiffel Tower is located in Paris.', "The Louvre is the world's most visited museum."]
3
🧠 Notice the count: we started with 3 documents,
appended one (→ 4), thenremoved one (→ 3). Tracking additions and removals like this is a good habit to build now — it’s the same mental math you’ll do when managing a growing conversation history or a document buffer later.
How It Works
[...]creates the list..append(x)addsxto the end..remove(x)deletes the first item equal tox.len(...)counts how many items are currently in the list.
🤖 How Is This Used in AI?
- Storing retrieved documents in a RAG pipeline
- Storing tokens produced by a tokenizer
- Storing conversation history (a list of messages)
- Storing search results returned from a vector database
conversation = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is Python?"}
]
That’s a list holding dictionaries — you’ll recognize this exact shape the moment you look at any LLM chat API’s request format.
⚠️ Common Beginner Mistakes
documents = ["a", "b", "c"]
print(documents[3]) # IndexError — valid indices are 0, 1, 2
Lists are zero-indexed: the first item is at position 0, not 1.
✅ Key Takeaway: A list is your default tool for “I have many of these, in a specific order, and the collection may grow or shrink.”
2. Tuples
What a List Stores
A tuple is like a list, but unchangeable (immutable) once created.
embedding_shape = (1, 1536)
Why One Variable Is Better Than Hundreds
Sometimes you want to guarantee a value can never accidentally be modified later in the program — e.g., a fixed configuration pair, or coordinates that should never drift.
Picture It as Numbered Boxes
A tuple is a sealed box — once packed, you can look inside, but you can’t swap what’s in it.
Example
model_config = ("gpt-4o-mini", 0.7) # (model_name, temperature)
model_name, temperature = model_config # unpacking
print(model_name)
print(temperature)
Expected Output:
gpt-4o-mini
0.7
⚠️ Common Beginner Mistake:
model_config[0] = "gpt-4o" # TypeError: 'tuple' object does not support item assignment
🤖 How Is This Used in AI?
- Embedding vector shapes:
(batch_size, embedding_dim) - Returning multiple fixed values from a function, e.g.
return answer, confidence_score - Anywhere you want to signal “this data should not change” — safer than a list for fixed structural information.
✅ Key Takeaway: Use a tuple when the collection’s size and content should be locked once created.
3. Sets
What Is It?
A set is an unordered collection of unique values — duplicates are automatically removed.
unique_words = {"python", "ai", "rag", "python"}
🧠 Intuition
A set is a bag with no duplicates allowed — if you try to throw in something that’s already there, nothing changes.
Example
# Deduplicating tokens from two overlapping documents
doc1_words = {"python", "is", "great", "for", "ai"}
doc2_words = {"python", "is", "used", "in", "ai"}
# Union: all unique words across both documents
all_words = doc1_words | doc2_words
print(all_words)
# Intersection: words that appear in both
shared_words = doc1_words & doc2_words
print(shared_words)
Expected Output:
{'python', 'is', 'great', 'for', 'ai', 'used', 'in'}
{'python', 'is', 'ai'}
Note: set printing order isn’t guaranteed — the values matter, not the order they appear in.
🤖 How Is This Used in AI?
- Deduplicating tokens or keywords
- Quickly checking membership:
if word in stopwords_set— sets check membership far faster than lists on large data - Comparing two documents’ vocabularies (union/intersection) — a simple but real technique in classic NLP preprocessing
✅ Key Takeaway: Reach for a set when order doesn’t matter and uniqueness does.
4. Dictionaries
What Is It?
A dictionary stores key–value pairs — you look things up by name, not by position.
metadata = {"source": "wikipedia", "page": 12, "verified": True}
Why Does It Exist?
Lists are great when position matters (“the 3rd item”). But a lot of
real-world data is labeled, not ordered — “give me the author” is far
more natural than “give me item 4.”
🧠 Intuition
A dictionary is a labeled filing cabinet — each drawer has a label (key), and you pull out exactly the drawer you name.
A Familiar Example
Think of a phone contact list: you look up a person by name (key), and you get their number (value) — not by remembering “contact #47.”
Syntax
my_dict = {"key1": value1, "key2": value2}
Example
# A single message in an LLM API request — this IS a dictionary
message = {
"role": "user",
"content": "What is retrieval-augmented generation?"
}
print(message["role"])
print(message["content"])
# Adding a new key
message["timestamp"] = "2026-08-14T10:00:00Z"
print(message)
# Safe lookup with .get() — won't crash if key is missing
print(message.get("model", "no model specified"))
Expected Output:
user
What is retrieval-augmented generation?
{'role': 'user', 'content': 'What is retrieval-augmented generation?', 'timestamp': '2026-08-14T10:00:00Z'}
no model specified
How It Works
message["role"]looks up the value stored under the key"role".message["timestamp"] = ...adds a brand-new key–value pair..get(key, default)looks up a key safely — if the key doesn’t exist, it returnsdefaultinstead of crashing.
🤖 How Is This Used in AI?
This is arguably the single most important collection type in AI development, because JSON and Python dictionaries are nearly identical in shape.
# This is exactly what an LLM API response looks like once parsed
api_response = {
"id": "msg_123",
"model": "gpt-4o-mini",
"content": [{"type": "text", "text": "Paris is the capital of France."}],
"usage": {"input_tokens": 24, "output_tokens": 9}
}
answer_text = api_response["content"][0]["text"]
tokens_used = api_response["usage"]["output_tokens"]
print(answer_text)
print(tokens_used)
Expected Output:
Paris is the capital of France.
9
Dictionaries appear everywhere:
- API requests/responses (JSON ↔ dict is nearly 1-to-1)
- document metadata (
source,page,author,score) - model configuration (
{"temperature": 0.7, "max_tokens": 500}) - tool/function arguments passed to an AI agent’s tools
⚠️ Common Beginner Mistake:
message["model"] # KeyError: 'model'Accessing a missing key with
[...]crashes the program. Use.get(...)when the key might not exist — this is exactly the kind of defensive habit you need once you’re parsing real (sometimes inconsistent) API responses.
✅ Key Takeaway: If you can read and build dictionaries confidently, you can read and build the JSON that every AI API speaks.
[!NOTE] Production Reality: Dictionaries vs. Pydantic Models While dictionaries are great for simple data mapping, in production AI codebases we rarely rely on raw dictionaries. If a model’s API returns a malformed dictionary or is missing a key, your code will crash with a
KeyErrorat runtime.To solve this, production frameworks (like FastAPI and LangChain) use Pydantic Models (derived from
BaseModel) which automatically parse and validate raw dictionaries, raising clean validation errors if fields are missing or have the wrong type. (We will cover this in detail in Module 14, but keep in mind that raw dicts are the raw inputs that Pydantic validates!)
5. Indexing and Slicing
What Is It?
Indexing grabs a single item by position. Slicing grabs a range of items. Here is a visual map showing positive and negative index positions for slicing:
| Value | “The” | “capital” | “of” | “France” | “is” | “Paris” |
|---|---|---|---|---|---|---|
| Positive Index | 0 | 1 | 2 | 3 | 4 | 5 |
| Negative Index | -6 | -5 | -4 | -3 | -2 | -1 |
tokens = ["The", "capital", "of", "France", "is", "Paris"]
print(tokens[0]) # first item
print(tokens[-1]) # last item
print(tokens[1:4]) # items at positions 1, 2, 3 (4 is excluded)
print(tokens[:3]) # first 3 items
print(tokens[3:]) # everything from position 3 onward
Expected Output:
The
Paris
['capital', 'of', 'France']
['The', 'capital', 'of']
['France', 'is', 'Paris']
🧠 Intuition: Slicing syntax [start:end] means “start here, stop
before end” — end is never included.
🤖 How Is This Used in AI?
- Splitting text into a fixed-size context window:
tokens[:512] - Grabbing the most recent N messages of a conversation for context:
conversation[-5:] - Chunking a long document into overlapping pieces for embedding — a core RAG preprocessing step.
6. Nested Collections
What Is It?
Collections can contain other collections — a list of dictionaries, a dictionary containing a list, etc. Real AI data is almost always nested.
Example
# A realistic shape: a list of retrieved documents, each with metadata
search_results = [
{"text": "Paris is the capital of France.", "score": 0.91, "source": "wiki"},
{"text": "The Eiffel Tower is in Paris.", "score": 0.85, "source": "wiki"},
{"text": "France uses the Euro currency.", "score": 0.62, "source": "wiki"},
]
# Get the text of the highest-scoring result (already sorted by score here)
top_result = search_results[0]
print(top_result["text"])
# Loop through and print only results above a relevance threshold
for result in search_results:
if result["score"] >= 0.8:
print(f"{result['score']} -> {result['text']}")
Expected Output:
Paris is the capital of France.
0.91 -> Paris is the capital of France.
0.85 -> The Eiffel Tower is in Paris.
We’re using a
forloop and anifhere slightly ahead of Module 3 — don’t worry about the exact mechanics yet, just notice the shape of the data: a list of dictionaries is the single most common data shape you’ll see in AI code.
🤖 How Is This Used in AI?
- Vector database search results: a list of dicts, each with
text,score, andmetadata - LLM chat history: a list of dicts, each with
roleandcontent - Full API responses: dicts containing lists containing dicts
✅ Key Takeaway: Once you’re comfortable reading results[0]["score"],
you can read the output of nearly any AI API or vector search call.
7. Mutable vs Immutable Objects
What Is It?
- Mutable = can be changed after creation (
list,dict,set) - Immutable = cannot be changed after creation (
str,int,float,tuple,bool)
Example
# Mutable: changing a list in place
tokens = ["a", "b", "c"]
tokens.append("d")
print(tokens) # ['a', 'b', 'c', 'd'] — same list, modified
# Immutable: "changing" a string actually creates a new one
text = "hello"
text_upper = text.upper()
print(text) # 'hello' — unchanged
print(text_upper) # 'HELLO' — a brand-new string
Expected Output:
['a', 'b', 'c', 'd']
hello
HELLO
⚠️ Common Beginner Mistake — the shared-reference trap:
history_a = ["hello"] history_b = history_a # NOT a copy — both names point to the SAME list history_b.append("world") print(history_a) # ['hello', 'world'] <- surprise!Visually, both variable names point to the exact same list object in memory. Modifying the list through either variable alters the shared object:
graph LR subgraph Memory References history_a[history_a] --> listObj[("List Object: ['hello', 'world']")] history_b[history_b] --> listObj endIf you need an independent copy, use
history_a.copy()orlist(history_a). This bug is a classic source of confusing behavior in agent code that passes conversation history around between functions.
🤖 How Is This Used in AI?
- Conversation history is usually a mutable list you deliberately append to as a chat progresses.
- Configuration you don’t want a function to accidentally alter is often passed as an immutable tuple.
- Understanding mutability is essential once you write functions that take a list of documents or messages as a parameter — you need to know whether modifying it inside the function affects the original data outside it (it does, for mutable types).
✅ Key Takeaway: Mutable = same box, contents can change. Immutable = sealed box, “changing” it really means getting a new box.
A Shallow Copy Does Not Copy Nested Objects
.copy() creates a new outer list or dictionary, but objects nested inside it
can still be shared:
original = {"settings": {"temperature": 0.2}}
copied = original.copy()
copied["settings"]["temperature"] = 0.8
print(original["settings"]["temperature"]) # 0.8
Both outer dictionaries contain a reference to the same inner settings
dictionary. Use copy.deepcopy() only when you truly need independent nested
objects; deep copying large AI payloads can consume considerable memory.
Choosing the Right Collection
Ask what job the collection must do:
| Need | Good choice | Example in an AI application |
|---|---|---|
| Keep items in order and allow changes | list | Conversation messages |
| Keep a fixed record | tuple | An image size such as (1024, 768) |
| Remove duplicates or test membership | set | Unique document IDs |
| Find a value by a meaningful key | dict | Model settings by name |
There is no collection that is best for every job. Choosing one that matches the operation makes the code easier to understand and often faster.
Module Summary
You now know the four core collection types — list (ordered, changeable), tuple (ordered, locked), set (unique, unordered), and dictionary (labeled key–value pairs) — plus how to reach inside them with indexing, slicing, and nesting, and the mutable/immutable distinction that explains a lot of “why did my data change unexpectedly” bugs.
AI Connection
Collections are the actual data structures flowing through every AI pipeline: documents in a list, metadata in a dict, a chat history as a list of dicts, an embedding shape as a tuple, a vocabulary as a set. JSON, the universal language of APIs, maps almost perfectly onto Python’s dict/list combination — which is exactly why this module matters so much for AI work specifically.
Mini Practice
- Build a list of 5 document strings, then use slicing to get the first 3.
- Build a dictionary representing one chat message (
role,content), then safely look up a"timestamp"key that doesn’t exist using.get(). - Given two sets of keywords from two documents, find the words unique to
each document (hint: look up the
-operator on sets). - Build a list of 4 dictionaries, each with
textandscorekeys, then write a loop that prints only the ones withscore > 0.7. - Explain, in one or two sentences, why passing a list into a function and modifying it there can affect the original list outside the function — and how you’d avoid that if you didn’t want it to happen.
Next: Module 3 — Control Flow (if/elif/else, loops) — how AI code makes decisions and processes data in batches.
- Author
- TechByteByByte Editorial Team
- Reviewed by
- TechByteByByte Admin
- Published
- Last reviewed