Python Basics

Lists & Dictionaries

Lists And Dictionaries

These two carry almost all the data in agent code. A list is things in order. A dictionary is things looked up by name. Between them they describe conversation history, tool arguments, API responses, retrieved documents and graph state.

Learn these properly and a large amount of framework code becomes readable.

Lists

An ordered, changeable collection.

skills = ["Python", "SQL", "Cloud"]

print(skills[0])
print(skills[-1])
print(len(skills))

skills.append("AI Agents")
print(skills)
Python
Cloud
3
['Python', 'SQL', 'Cloud', 'AI Agents']

Counting from zero, and counting backwards

This is worth doing slowly, because it catches everyone once.

students = ["Amit", "Sara", "John", "Anil"]

print(students[0])
print(students[2])
print(students[-1])
print(students[10])
  • students[0] is the first item, not the second. Counting starts at zero.
  • students[-1] is the last. In Java or C# that would throw; Python treats it as counting from the end, and it is genuinely useful.
  • students[10] raises IndexError, because there is no eleventh student. That error is Python working correctly, not your notebook being broken.

The methods you need

items = ["a", "b", "c"]

items.append("d")
items.insert(0, "z")
items.remove("b")
last = items.pop()
items.sort()
items.reverse()
print("a" in items)
print(items.index("c"))
MethodDoes
.append(x)add to the end
.insert(i, x)add at a position
.remove(x)remove the first matching value
.pop()remove and return the last item
.sort()sort in place
inis it present
.index(x)where is it

Note that .sort() changes the list and returns None. sorted(items) returns a new sorted list and leaves the original alone. Writing items = items.sort() sets items to None, which is a memorable afternoon.

Slicing

items = ["a", "b", "c", "d", "e"]

print(items[:2])
print(items[2:])
print(items[-2:])

Same rules as strings. items[:2] is up to but not including position 2.

Slicing a list gives a new list, which is the shortest way to copy one:

copy = items[:]

Dictionaries

Values looked up by name rather than position.

member = {
    "name": "Priya",
    "role": "Data Architect",
    "years": 14,
}

print(member["role"])

member["city"] = "Pune"
print(member)

Curly braces, key: value pairs, commas between. Keys are usually strings.

Missing keys

print(member["salary"])
KeyError: 'salary'

Square brackets demand the key exists. When it might not, use .get():

print(member.get("salary"))
print(member.get("salary", "not disclosed"))

.get() returns None when the key is absent, or the default you supply.

For anything that came from a model or an external API, assume keys may be missing. This single habit removes most crashes in early agent code.

Walking a dictionary

for key in member:
    print(key)

for key, value in member.items():
    print(key, "=", value)

print(list(member.keys()))
print(list(member.values()))

Looping a dictionary directly gives you the keys. When you want both, use .items(). Forgetting that is a common early error.

Useful bits

print("role" in member)
member.update({"years": 15, "tier": "diamond"})
member.pop("city", None)

in checks keys, not values. .pop(key, None) removes safely whether or not the key was there.

Nesting, which is where real data lives

Real responses are dictionaries inside dictionaries, and lists of dictionaries.

response = {
    "status": "success",
    "ticket": {
        "id": 4471,
        "severity": "P2",
        "tags": ["network", "urgent"],
    },
}

print(response["ticket"]["severity"])
print(response["ticket"]["tags"][0])

Work left to right, one step at a time. response["ticket"] is a dictionary, so you can index it again. ["tags"] is a list, so you index it by position.

When you are unsure of the shape, print it laid out:

import json
print(json.dumps(response, indent=2))

That one line will save you more debugging time than anything else on this page.

The shape you will see most often

A list of dictionaries. It is the standard format for conversation history and for rows of anything.

messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Why is the server down?"},
    {"role": "assistant", "content": "Let me check the logs."},
]

for m in messages:
    print(f"{m['role']}: {m['content']}")

messages.append({"role": "user", "content": "Thanks"})
print(len(messages))

Note the single quotes inside the f-string braces — the outer string already uses double quotes, so the inner ones must differ.

This exact structure is what every chat API accepts, what LangGraph carries in state["messages"], and what you will read and write hundreds of times.

Tuples and sets, briefly

point = (12, 45)
unique_owners = {"network", "database", "network"}
print(unique_owners)
  • a tuple is a list that cannot be changed. Used for fixed pairs and for returning several values
  • a set has no duplicates and no order. Used for de-duplicating

Neither is as common as lists and dictionaries in agent code, but you will see them.

Coming from Java or C#

ConceptJavaC#Python
Growable listArrayList<T>List<T>list
MapHashMap<K,V>Dictionary<K,V>dict
SetHashSet<T>HashSet<T>set
Fixed pairno clean formTupletuple
Size.size(), .Countlen(x)
Add.add(x).Add(x).append(x)
Get by key.get(k)[k][k] or .get(k)
Missing keyreturns nullthrows[k] throws, .get(k) returns None
Contains.contains(x).Contains(x)x in y

Three differences worth holding on to:

  • a Python list holds anything, including a mixture. There is no List<String> at runtime, only list
  • len() is a function, not a method
  • map.get(k) in Java returns null for a missing key; Python's d[k] throws. .get() is the forgiving one

Common mistakes

  • items = items.sort(), which sets it to None. Use sorted() or just call .sort().
  • d["key"] on data you did not create. Use .get().
  • Looping a dictionary and expecting pairs. You get keys; use .items().
  • Expecting b = a to copy. It does not. Use a.copy() or a[:].
  • Modifying a list while looping over it, which skips items. Build a new list instead.
  • Assuming order in a set. There is none.

Practise this

  • Build a list of four names. Print the first, the last, and the length. Then trigger an IndexError.
  • Build a dictionary describing yourself. Read one key that exists and one that does not, safely.
  • Build a list of three message dictionaries and print each as role: content.
  • Read a value three levels deep out of a nested response, then print the whole thing with indent=2.

Try It Yourself

Copy this into a new Colab notebook and run it. Nothing to install.

example.py
1# Lists - conversation history
2messages = []
3
4# Add messages to history
5messages.append({"role": "system", "content": "You are helpful."})
6messages.append({"role": "user", "content": "What is Python?"})
7messages.append({"role": "assistant", "content": "Python is a programming language."})
8
9# Access messages
10print("First message:", messages[0])
11print("Last message:", messages[-1])
12print("Total messages:", len(messages))
13
14# Dictionary - API message format
15api_request = {
16 "model": "deepseek-chat",
17 "messages": messages,
18 "temperature": 0.7,
19 "max_tokens": 500
20}
21
22print("\nAPI Request:")
23for key, value in api_request.items():
24 print(f" {key}: {value}")
25
26# Nested access
27print("\nModel being used:", api_request["model"])
28print("Number of messages:", len(api_request["messages"]))
29
30# Safe access with .get()
31stream = api_request.get("stream", False) # Default to False
32print(f"Streaming enabled: {stream}")