Chapter 02 · Section I · 26 min read
The data shapes: lists, dictionaries, and tables
Three shapes account for almost every piece of data you will work with in this track. Get comfortable with them now and most real code becomes legible.
In the last chapter you stored a name and a greeting in two separate variables. That works when you have two things. When you have two hundred — two hundred Khalti transactions, two hundred days of NEPSE prices, two hundred student records — you need a shape to hold them in. Most real programs are mostly about choosing the right shape and then moving data through it.
The three shapes that cover almost everything
There are exactly three you will use over and over:
- A list — an ordered sequence of items.
- A dictionary — a set of named properties.
- A list of dictionaries — a table. A collection of things, each with named properties.
Almost every dataset in this track collapses into one of those three. Learn them once carefully and the rest of the track speeds up.
A list
A list is what it sounds like. An ordered sequence. You write it with square brackets and commas:
expenses = [120, 80, 250, 90, 45]
Now expenses holds five numbers. A few useful operations:
expenses[0] # 120 — the first item
expenses[-1] # 45 — the last item
len(expenses) # 5 — how many items
expenses.append(300) # adds 300 to the end
expenses[1:3] # [80, 250] — items from index 1 up to (not including) 3
A few things worth carrying with you:
- Lists are zero-indexed. The first item is
expenses[0], notexpenses[1]. This trips up almost everyone for a week. The world is wrong; programming languages mostly agree on starting from zero. - You can hold anything in a list — numbers, strings, other lists, mixed types. Most real-world lists hold one kind of thing.
len(...)tells you how many..append(...)adds to the end. These two and zero-indexing get you through 80% of list work.
A dictionary
A dictionary holds named properties of a single thing. Curly braces, key-value pairs, separated by commas:
transaction = {
"vendor": "Khalti",
"amount": 5000,
"date": "2026-06-25",
"approved": True,
}
You access values by key, not by position:
transaction["vendor"] # "Khalti"
transaction["amount"] # 5000
You can add or change values by assignment:
transaction["status"] = "settled"
transaction["amount"] = 5050
The right time to reach for a dictionary is when a single thing has several named pieces — a person has a name and an age and a district; a transaction has a vendor and an amount and a date. If you find yourself writing three variables that all describe the same thing — vendor, amount, date — that is a dictionary trying to happen.
A list of dictionaries: the table shape
This is the single most useful shape in all of data work. It is what almost every real dataset is, before someone wraps it in a fancier name:
transactions = [
{"vendor": "Khalti", "amount": 5000, "date": "2026-06-25"},
{"vendor": "eSewa", "amount": 1200, "date": "2026-06-25"},
{"vendor": "Khalti", "amount": 450, "date": "2026-06-26"},
{"vendor": "FonePay", "amount": 900, "date": "2026-06-26"},
]
This is a table. Each dictionary is a row. The keys (vendor, amount, date) are the columns. It is the same shape as a spreadsheet, the same shape as a NEPSE export, the same shape as a CSV file you will read in Section 3.
Once you have it, common questions are easy to ask. To list every vendor:
for t in transactions:
print(t["vendor"])
To total all amounts:
total = 0
for t in transactions:
total = total + t["amount"]
print(total) # 7550
You will write code shaped like this every week for the rest of the track.
A quick comparison
A small table to keep straight:
| Shape | Use it for | Example |
|---|---|---|
| List | An ordered sequence of similar items | [120, 80, 250] — five expenses |
| Dictionary | Named properties of a single thing | {"vendor": "Khalti", "amount": 5000} |
| List of dictionaries | A collection of things, each with named properties | One row per transaction |
If you ever feel stuck choosing a shape, ask: am I holding a sequence, a single thing’s properties, or a collection of such things?
A worked piece of code to read carefully
Before the quiz, one small program to sit with. It uses all three shapes:
transactions = [
{"vendor": "Khalti", "amount": 5000},
{"vendor": "eSewa", "amount": 1200},
{"vendor": "Khalti", "amount": 450},
{"vendor": "FonePay", "amount": 900},
]
vendors = []
for t in transactions:
vendors.append(t["vendor"])
print(vendors)
Predict the output before you run it.
The expected output is:
['Khalti', 'eSewa', 'Khalti', 'FonePay']
Read it once more. The list of dictionaries is the input. The list of strings is the output. The dictionary access (t["vendor"]) and the list append (vendors.append(...)) are the two operations that move data from one shape to the other. This is the rhythm of almost every data-shaping task in this track.
Check your understanding
Quick check
—A friend writes this program: prices = [200, 180, 220, 190] print(prices[1]) What does it print?
Quick check
—You have this data: people = [ {'name': 'Anu', 'district': 'Kaski'}, {'name': 'Bikas', 'district': 'Morang'}, ] Which expression gives the string 'Morang'?
What comes next
You now have shapes to hold data in. The next section gives you the tools to move data through them: functions to give a piece of work a name, and loops to do the same work many times without copy-pasting. The two together turn a list of dictionaries into something you can compute on.