One Variable, Many Items
Every Sunday, Amma writes the list for the weekly vegetable market: tomatoes, onions, potatoes, coriander, bananas. On the way, she remembers garlic and adds it at the bottom. At the market, the potatoes look bad, so she crosses them out. At home, she counts how many items she bought and adds up the bill.
If you stored that list in Python with one variable per item, you would need item1, item2, item3 and so on. Adding, removing or counting would be painful. Python has a much better tool: the list. A list stores many values in one variable, in a fixed order, and you can add, remove, sort and count items easily.
Lists are one of the most used parts of Python. In this lesson we will follow Amma’s market list, and finish with a class marks report that a teacher could really use.
Step 1: Creating a List
Write the items inside square brackets [ ], separated by commas. A list can hold strings, numbers or any other values. It can even be empty, ready to fill later. The len() function tells you how many items are in a list.
shopping = ["tomatoes", "onions", "potatoes", "coriander", "bananas"]
prices = [40, 35, 30, 10, 60]
empty_bag = []
mixed = ["rice", 2, 54.5, True] # allowed, but not common
print(shopping) # ['tomatoes', 'onions', 'potatoes', 'coriander', 'bananas']
print(len(shopping)) # 5
print(len(empty_bag)) # 0
print(type(prices)) # <class 'list'>
Step 2: Indexing and Slicing
Every item has a position number called an index. Python starts counting at 0, so the first item is shopping[0]. This feels strange at first, but you get used to it quickly. You can also count from the end with negative indexes: -1 is the last item, -2 the second last.
A slice takes a part of the list: shopping[1:3] gives the items from index 1 up to, but not including, index 3. This is the same “stop is not included” rule as range() in the Loops lesson and slicing strings in the Strings lesson.
shopping = ["tomatoes", "onions", "potatoes", "coriander", "bananas"]
# index: 0 1 2 3 4
# negative: -5 -4 -3 -2 -1
print(shopping[0]) # tomatoes (the first item)
print(shopping[2]) # potatoes
print(shopping[-1]) # bananas (the last item)
# Slicing: [start:stop], the stop index is not included
print(shopping[1:3]) # ['onions', 'potatoes']
print(shopping[:2]) # ['tomatoes', 'onions'] (from the start)
print(shopping[3:]) # ['coriander', 'bananas'] (to the end)
print(shopping[::2]) # ['tomatoes', 'potatoes', 'bananas'] (every second item)
Step 3: Changing, Adding and Removing Items
Unlike strings, lists are mutable: you can change them after you create them. To replace an item, assign to its index. To add and remove items, lists have built-in methods, which you call with a dot after the list name:
| Method | What it does |
|---|---|
append(x) | Adds x at the end |
insert(i, x) | Adds x at index i and moves the rest to the right |
extend(other) | Adds every item of another list at the end |
remove(x) | Removes the first item equal to x |
pop() / pop(i) | Removes the last item (or the item at i) and gives it back to you |
index(x) | Gives the position of the first item equal to x |
shopping = ["tomatoes", "onions", "potatoes"]
shopping[1] = "red onions" # change one item
print(shopping) # ['tomatoes', 'red onions', 'potatoes']
shopping.append("garlic") # add at the end
print(shopping) # ['tomatoes', 'red onions', 'potatoes', 'garlic']
shopping.insert(0, "spinach") # add at position 0
print(shopping) # ['spinach', 'tomatoes', 'red onions', 'potatoes', 'garlic']
shopping.extend(["lemons", "ginger"]) # add many items at the end
print(len(shopping)) # 7
shopping.remove("potatoes") # remove by value (the first match)
print(shopping) # ['spinach', 'tomatoes', 'red onions', 'garlic', 'lemons', 'ginger']
last = shopping.pop() # remove and give back the last item
print(last) # ginger
first = shopping.pop(0) # remove and give back the item at index 0
print(first) # spinach
print(shopping) # ['tomatoes', 'red onions', 'garlic', 'lemons']
Step 4: Is It on the List? Using in
Before buying something, Amma checks her list. The in keyword does the same: it gives True if a value is in the list and False if not. not in does the opposite. It works well with if to avoid adding the same item twice.
shopping = ["tomatoes", "onions", "coriander"]
print("onions" in shopping) # True
print("ginger" in shopping) # False
print("ginger" not in shopping) # True
item = "coriander"
if item in shopping:
print(f"{item} is already on the list")
else:
shopping.append(item)
Step 5: Sorting Lists
Python gives you two ways to sort, and the difference matters:
sorted(my_list)is a function. It gives back a new sorted list and leaves the original as it was.my_list.sort()is a method. It sorts the list itself and gives backNone.
Both accept reverse=True for largest first. Both also accept key=, which tells Python what to compare. With key=len, Python compares the length of each word instead of the word itself.
prices = [40, 35, 30, 10, 60]
veg = ["tomatoes", "okra", "cabbage", "peas"]
# sorted() gives a NEW sorted list and keeps the original
cheap_first = sorted(prices)
print(cheap_first) # [10, 30, 35, 40, 60]
print(prices) # [40, 35, 30, 10, 60] (unchanged)
# .sort() changes the list itself and gives back None
prices.sort(reverse=True)
print(prices) # [60, 40, 35, 30, 10]
print(sorted(veg)) # ['cabbage', 'okra', 'peas', 'tomatoes'] (A to Z)
print(sorted(veg, key=len)) # ['okra', 'peas', 'cabbage', 'tomatoes'] (shortest first)
veg.reverse() # just flips the current order
print(veg) # ['peas', 'cabbage', 'okra', 'tomatoes']
Step 6: Looping, enumerate, sum, min and max
You already know how to loop over a list with for. When you also need the position of each item, use enumerate(). It gives you two values each time: a counter and the item. start=1 makes the counter begin at 1, which looks more natural for people.
For lists of numbers, Python has three ready-made helpers: sum(), min() and max(). They save you from writing the accumulator loop yourself.
shopping = ["tomatoes", "onions", "potatoes"]
prices = [40, 35, 30]
for item in shopping:
print(f"- {item}")
# enumerate gives the position and the item together
for number, item in enumerate(shopping, start=1):
print(f"{number}. {item}")
# 1. tomatoes
# 2. onions
# 3. potatoes
print(sum(prices)) # 105
print(min(prices)) # 30
print(max(prices)) # 40
print(f"Average price: Rs. {sum(prices) / len(prices):.2f}") # Rs. 35.00
Step 7: Nested Lists: A Small Marks Table
A list can contain other lists. This is a simple way to store a table: each inner list is one row. To reach a single value, use two indexes: the first picks the row, the second picks the column. So marks[1][2] means “row 1, column 2”.
# Each inner list is one student: [name, maths, science, english]
marks = [
["Aarav", 78, 85, 69],
["Diya", 92, 88, 95],
["Ishaan", 55, 61, 48],
]
print(marks[1]) # ['Diya', 92, 88, 95]
print(marks[1][0]) # Diya
print(marks[1][2]) # 88 (Diya's science marks)
for row in marks:
name = row[0]
total = sum(row[1:])
print(f"{name}: {total}")
# Aarav: 232
# Diya: 275
# Ishaan: 164
In the Dictionaries lesson you will learn a clearer way to label each value with a name instead of a column number.
Step 8: The Copying Trap
This one surprises almost every beginner. When you write tuesday = monday, Python does not copy the list. It gives the same list a second name. Think of two people holding the same notebook: whatever one writes, the other sees. To get a separate list, make a real copy with .copy().
monday = ["milk", "bread"]
tuesday = monday # NOT a copy: both names point to the same list
tuesday.append("eggs")
print(monday) # ['milk', 'bread', 'eggs'] (surprise!)
# Make a real copy instead
wednesday = monday.copy() # or monday[:] or list(monday)
wednesday.append("paneer")
print(monday) # ['milk', 'bread', 'eggs'] (unchanged)
print(wednesday) # ['milk', 'bread', 'eggs', 'paneer']
A variable does not hold the list itself. It points to the list. Two variables can point to the same list, so a change through one name shows up through the other. Use .copy() when you want two separate lists.
Real-Life Example: Class Marks Report
Mrs. Iyer teaches maths to Class 10 B. She keeps the names in one list and the marks in another, in the same order. With a few lines, she gets a full report: who passed, the class average, the topper, and who scored above average.
names = ["Aarav", "Diya", "Ishaan", "Meera", "Kabir", "Sana"]
marks = [78, 92, 31, 66, 54, 88]
PASS_MARK = 35
print("=== Class 10 B: Maths Results ===")
for i, name in enumerate(names):
status = "Pass" if marks[i] >= PASS_MARK else "Needs support"
print(f"{i + 1}. {name:<8} {marks[i]:>3} {status}")
average = sum(marks) / len(marks)
topper = names[marks.index(max(marks))]
above_average = [names[i] for i in range(len(names)) if marks[i] > average]
print(f"Class average: {average:.1f}")
print(f"Highest: {max(marks)} by {topper}")
print(f"Lowest: {min(marks)}")
print(f"Above average: {above_average}")
print(f"Top three marks: {sorted(marks, reverse=True)[:3]}")
Run it and you will see a class average of 68.2, Diya as the topper with 92, and Ishaan marked “Needs support”. A few new things appear here. {name:<8} inside an f-string pads the name to 8 characters so the columns line up, and {marks[i]:>3} lines numbers up on the right. marks.index(max(marks)) finds the position of the highest mark, and that position gives the topper’s name. The line that builds above_average is a list comprehension, a short way to build a list with a loop inside square brackets. You will study it properly in the Comprehensions lesson; for now, read it as “the names of students whose marks are above the average”.
Try these changes:
- Add a seventh student with
append()on both lists and run the report again. - Change the pass mark to 60 and see how the statuses change.
- Print the names sorted from A to Z with
sorted(names).
Common Mistakes
- Using an index that does not exist. A list of 3 items has indexes 0, 1 and 2. Asking for index 3 gives an
IndexError. Useshopping[-1]for the last item, or checklen()first.
shopping = ["tomatoes", "onions", "potatoes"]
print(shopping[3]) # ERROR: IndexError
- Saving the result of
.sort()..sort()changes the list and gives backNone. If you want a new list, usesorted():
prices = [40, 35, 30]
result = prices.sort()
print(result) # None (sort changes the list but gives back nothing)
prices = [40, 35, 30]
result = sorted(prices)
print(result) # [30, 35, 40]
- Using
append()for many items.shopping.append(["lemons", "ginger"])adds one item, a whole list inside your list. Useextend()to add the items one by one. - Thinking
b = amakes a copy. It does not. Useb = a.copy(). - Removing an item that is not there.
remove("ginger")gives aValueErrorif ginger is not in the list. Check withif "ginger" in shopping:first.
Practice Task: Amma’s Market Bill
You have two lists in the same order: item names and their prices. Complete the starter code so that it:
- Adds bananas (Rs. 60) to the end of both lists
- Removes coriander and its price from both lists
- Prints a numbered list with prices, using
enumerate() - Prints the total, the cheapest and the most expensive price
- Prints the names from A to Z without changing the original list
market_list = ["tomatoes", "onions", "potatoes", "coriander"]
prices = [40, 35, 30, 10]
# TODO 1: Add "bananas" (price 60) to the end of both lists
# TODO 2: You found coriander at home. Remove it and its price
# (hint: use index() to find its position, then pop() from both lists)
# TODO 3: Print the list as a numbered list with prices, for example: 1. tomatoes: Rs. 40
# TODO 4: Print the total, the cheapest and the most expensive price
# TODO 5: Print the item names sorted from A to Z, without changing market_list
Show one possible answer (try it yourself first!)
market_list = ["tomatoes", "onions", "potatoes", "coriander"]
prices = [40, 35, 30, 10]
market_list.append("bananas")
prices.append(60)
position = market_list.index("coriander")
market_list.pop(position)
prices.pop(position)
for number, item in enumerate(market_list, start=1):
print(f"{number}. {item}: Rs. {prices[number - 1]}")
# 1. tomatoes: Rs. 40
# 2. onions: Rs. 35
# 3. potatoes: Rs. 30
# 4. bananas: Rs. 60
print(f"Total: Rs. {sum(prices)}") # Total: Rs. 165
print(f"Cheapest: Rs. {min(prices)}") # Cheapest: Rs. 30
print(f"Costliest: Rs. {max(prices)}") # Costliest: Rs. 60
print(sorted(market_list)) # ['bananas', 'onions', 'potatoes', 'tomatoes']
print(market_list) # ['tomatoes', 'onions', 'potatoes', 'bananas']
Key Takeaways
- A list stores many values in order, inside square brackets.
len()counts them. - Indexes start at 0, negative indexes count from the end, and slices like
[1:3]do not include the stop index. append,insert,extend,removeandpopchange a list.inchecks if a value is in it.sorted()gives a new list;.sort()changes the list itself. Both acceptreverse=Trueandkey=.b = adoes not copy a list. Usea.copy()for a separate list.