Learn
🤖 AI Hub 📰 News 📖 Dictionary 🧰 Resources
Grow
💼 Jobs 🚀 Community 🏆 Challenges
Explore by Stage
🌑 Zero 📚 Learn 🔧 Practice 🏗 Build 🚀 Launch 💰 Earn
Account
Login Sign Up
🏗️HTML 🎨CSS ⚡JavaScript 🐙Git & GitHub ⚛️React Soon 📘TypeScript Soon 🐍Python 🗄️Database & SQL Soon 🌐Web Development Soon ☁️Cloud & DevOps Soon 🤖AI & ML Soon 📄Resume Prep Soon 🎤Interview Prep Soon 💼Freelancing Soon 🚀SaaS & Side Projects Soon 🤖Automation Soon
Beginner 🕑 11 min read 👁 3 views 📅 Oct 22, 2026

Lists: Storing Many Items in Order

Store many values in one Python list, read them by index and slice, add and remove items, sort them and loop with enumerate. You will build a class marks report for a teacher.

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:

MethodWhat 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 back None.

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:

  1. Add a seventh student with append() on both lists and run the report again.
  2. Change the pass mark to 60 and see how the statuses change.
  3. 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. Use shopping[-1] for the last item, or check len() first.
shopping = ["tomatoes", "onions", "potatoes"]
print(shopping[3])  # ERROR: IndexError
  • Saving the result of .sort(). .sort() changes the list and gives back None. If you want a new list, use sorted():
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. Use extend() to add the items one by one.
  • Thinking b = a makes a copy. It does not. Use b = a.copy().
  • Removing an item that is not there. remove("ginger") gives a ValueError if ginger is not in the list. Check with if "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, remove and pop change a list. in checks if a value is in it.
  • sorted() gives a new list; .sort() changes the list itself. Both accept reverse=True and key=.
  • b = a does not copy a list. Use a.copy() for a separate list.

❓ Frequently Asked Questions

The index is the distance from the start of the list. The first item is 0 steps from the start, so its index is 0. Most programming languages count this way.
Yes. A list can mix strings, numbers and other values. In practice, keeping one type per list, such as only names or only prices, makes your code much easier to work with.
remove() deletes an item by its value. pop() deletes an item by its position and gives that item back to you, so you can still use it.
Use sorted() when you want to keep the original order as well. Use .sort() when you no longer need the original order and want to change the list itself.
Was this lesson helpful?

🎯 Finished this lesson?

🔗 Related Tutorials
🤖 Got a Doubt? Ask AI
Get instant answers in Hindi or English
🤖
Z2T Bot
Online
Ask me anything about this tutorial — I'm here! 👋