Sitemap
Ajay Narayan

Ajay Narayan

Just a Python enthusiast sharing what I learn and discover along the way.

Python Lists: How to Store a Hundred Things in One Variable

8 min readOct 23, 2026

--

Indexing, slicing, adding, removing, sorting, plus the two sneaky bugs that catch every beginner.

Press enter or click to view image in full size

Hey again! 👋

Confession time: I’ve been using lists on you for two posts now without properly introducing them.

Remember these from the loops post?

fruits = ["apple", "banana", "cherry"]
contacts = ["Alice", "Bob", "Charlie", "Diana", "Ethan"]

We looped over them, searched through them, even built new ones with .append(). And it all just… worked. But we never stopped to ask: what actually is a list, and what else can it do?

Today we fix that.

Here’s why it matters. Imagine tracking marks for a class of 40 students. Without lists, you’d need mark1, mark2, mark3… all the way to mark40. Then try finding the highest one. 😵

With a list, it’s one variable and one line: max(marks).

Lists are probably the data structure you’ll use most in your entire Python life. Let’s get really comfortable with them.

What You’ll Master Today

By the end of this post, you’ll be able to:

✅ Create lists and access items by position (including from the end!)

✅ Slice out parts of a list

✅ Add, change, and remove items

✅ Sort lists, and avoid the None trap

✅ Use len, sum, min, max, and in like a pro

✅ Write your first list comprehension

✅ Build a working To-Do List app

Prerequisites: Everything so far, especially Loops and Functions. Today’s mini project leans on both.

Part 1: Creating Lists

A list is an ordered collection of items, written inside square brackets and separated by commas:

fruits = ["apple", "banana", "cherry"]
scores = [85, 92, 78]
mixed = ["Ajay", 25, True, 3.14]
empty = []

Lists can hold anything: strings, numbers, booleans, even a mix. (In practice, most lists hold one type of thing. A list of scores, a list of names.)

Part 2: Indexing — Grabbing One Item

Every item in a list has a position number called an index. And just like range() from the loops post, counting starts at 0.

fruits = ["apple", "banana", "cherry"]

print(fruits[0])
print(fruits[1])
print(fruits[2])

# Output:
# apple
# banana
# cherry

Ask for a position that doesn’t exist and Python complains:

print(fruits[3])

# IndexError: list index out of range

Three items means indexes 0, 1, and 2. There is no index 3. You’ll see this error a lot while learning. Now you know exactly what it means.

Negative indexing: counting from the end

Here’s a Python trick people love:

print(fruits[-1])
print(fruits[-2])

# Output:
# cherry
# banana

-1 is always the last item, -2 is second-to-last, and so on. No need to know how long the list is. Super handy.

Part 3: Slicing — Grabbing Many Items

Want a chunk of a list instead of one item? Use a slice: list[start:stop].

numbers = [10, 20, 30, 40, 50, 60]

print(numbers[1:4])
print(numbers[:3])
print(numbers[3:])

# Output:
# [20, 30, 40]
# [10, 20, 30]
# [40, 50, 60]

Same rule as range(): the start is included, the stop is not. Leave out the start and it begins from the beginning; leave out the stop and it goes to the end.

Add a third number for the step:

print(numbers[::2])
print(numbers[::-1])

# Output:
# [10, 30, 50]
# [60, 50, 40, 30, 20, 10]

That [::-1] reverses a list. It's one of the most-Googled Python tricks of all time, and now you don't need to Google it. 😎

Part 4: Changing Lists

Here’s a big difference between lists and strings: lists are mutable, which means you can change them after creating them.

fruits = ["apple", "banana", "cherry"]
fruits[1] = "blueberry"
print(fruits)

# Output:
# ['apple', 'blueberry', 'cherry']

Try the same with a string and Python says no:

name = "Ajay"
name[0] = "B"

# TypeError: 'str' object does not support item assignment

Adding items

cart = ["milk", "bread"]

cart.append("eggs") # add to the end
print(cart)

cart.insert(0, "coffee") # add at a position
print(cart)

cart.extend(["rice", "salt"]) # add several at once
print(cart)

# Output:
# ['milk', 'bread', 'eggs']
# ['coffee', 'milk', 'bread', 'eggs']
# ['coffee', 'milk', 'bread', 'eggs', 'rice', 'salt']

Removing items

cart = ["coffee", "milk", "bread", "eggs", "rice", "salt"]

cart.remove("bread") # remove by value
print(cart)

last = cart.pop() # remove and return the last item
print(last, cart)

first = cart.pop(0) # remove and return the item at index 0
print(first, cart)

del cart[1] # delete by index
print(cart)

# Output:
# ['coffee', 'milk', 'eggs', 'rice', 'salt']
# salt ['coffee', 'milk', 'eggs', 'rice']
# coffee ['milk', 'eggs', 'rice']
# ['milk', 'rice']

Quick guide:

  • Know the value? Use .remove()
  • Know the position and want the item back? Use .pop()
  • Just want it gone? Use del

One warning: .remove() crashes if the item isn't there (ValueError: list.remove(x): x not in list). Check first with in:

if "bread" in cart:
cart.remove("bread")

Part 5: Super-Useful List Tools

scores = [85, 92, 78, 92, 64]

print(len(scores)) # how many items
print(max(scores)) # highest
print(min(scores)) # lowest
print(sum(scores)) # total
print(sum(scores) / len(scores)) # average
print(scores.count(92)) # how many times 92 appears
print(scores.index(78)) # position of 78
print(92 in scores) # is 92 in the list?

# Output:
# 5
# 92
# 64
# 411
# 82.2
# 2
# 2
# True

Remember writing the accumulator pattern to add numbers in the loops post? sum() does that for you in one word. It's still worth knowing how to write the loop yourself, because you'll need that pattern for things Python doesn't have a built-in for.

Sorting (and the None trap)

There are two ways to sort:

scores = [85, 92, 78, 92, 64]

scores.sort() # sorts the list itself
print(scores)

scores.sort(reverse=True) # biggest first
print(scores)

names = ["Zoe", "ajay", "Bob"]
print(sorted(names)) # returns a NEW sorted list
print(names) # original is untouched

# Output:
# [64, 78, 85, 92, 92]
# [92, 92, 85, 78, 64]
# ['Bob', 'Zoe', 'ajay']
# ['Zoe', 'ajay', 'Bob']

(Notice 'ajay' came last? Python sorts uppercase letters before lowercase. Use sorted(names, key=str.lower) to sort them the way a human would.)

Get Ajay Narayan’s stories in your inbox

Join Medium for free to get updates from this writer.

Now the trap. Remember from the functions post that a function with no return gives back None? Well, .sort() changes the list in place and returns None:

scores = [85, 92, 78]
scores = scores.sort()
print(scores)

# Output:
# None

Oops, we just replaced our whole list with None. 😬 Rule: use .sort() on its own line, or use sorted() if you need a new list.

Part 6: The Copy Trap

This one confuses even people who’ve been coding for a while:

a = [1, 2, 3]
b = a
b.append(4)

print(a)

# Output:
# [1, 2, 3, 4]

Wait, we changed b, so why did a change?!

Because b = a doesn't copy the list. It just gives the same list a second name. Think of it like two people sharing one Google Doc. Either of them edits, both see it.

If you want a real, separate copy:

a = [1, 2, 3]
b = a.copy()
b.append(4)

print(a)
print(b)

# Output:
# [1, 2, 3]
# [1, 2, 3, 4]

Part 7: Looping Like a Pro

You already know for item in my_list. But what if you also need the position number? Use enumerate():

tasks = ["Study Python", "Buy groceries", "Call mom"]

for number, task in enumerate(tasks, start=1):
print(f"{number}. {task}")

# Output:
# 1. Study Python
# 2. Buy groceries
# 3. Call mom

enumerate hands you both the count and the item, and start=1 makes it count like a human instead of from 0.

Your first list comprehension

Remember the accumulator pattern for building a new list?

numbers = [1, 2, 3, 4, 5]
squares = []
for n in numbers:
squares.append(n * n)

Python has a shortcut for exactly this, called a list comprehension:

numbers = [1, 2, 3, 4, 5]

squares = [n * n for n in numbers]
evens = [n for n in numbers if n % 2 == 0]

print(squares)
print(evens)

# Output:
# [1, 4, 9, 16, 25]
# [2, 4]

Read it like a sentence: “give me n * n for each n in numbers." If it feels weird at first, that's normal. Use the regular loop until the shortcut feels natural. Both are correct.

Real-World: Class Marks Analyzer

marks = [72, 88, 45, 91, 60, 38, 79]
pass_mark = 40

passed = [m for m in marks if m >= pass_mark]
failed = [m for m in marks if m < pass_mark]
average = sum(marks) / len(marks)

print("Class Report")
print("-" * 40)
print(f"Students: {len(marks)}")
print(f"Highest: {max(marks)}")
print(f"Lowest: {min(marks)}")
print(f"Average: {average:.2f}")
print(f"Passed: {len(passed)}/{len(marks)}")
print(f"Failed marks: {failed}")

# Output:
# Class Report
# ----------------------------------------
# Students: 7
# Highest: 91
# Lowest: 38
# Average: 67.57
# Passed: 6/7
# Failed marks: [38]

Try doing that with 7 separate variables. 😄

Mini Project: To-Do List Manager

Time to combine lists, loops, conditions, and functions into a real little app:

def show_tasks(tasks):
if not tasks:
print("\nNo tasks yet. Enjoy the free time! 🎉")
return
print("\nYour tasks:")
for number, task in enumerate(tasks, start=1):
print(f" {number}. {task}")

def add_task(tasks):
task = input("New task: ").strip()
if task:
tasks.append(task)
print(f"Added: {task}")
else:
print("Task can't be empty.")

def complete_task(tasks):
show_tasks(tasks)
if not tasks:
return
number = int(input("Task number to complete: "))
if 1 <= number <= len(tasks):
done = tasks.pop(number - 1)
print(f"Completed: {done} ✅")
else:
print("That task number doesn't exist.")

def main():
tasks = []
print("=" * 50)
print("TO-DO LIST MANAGER")
print("=" * 50)

while True:
print("\n1. View tasks")
print("2. Add task")
print("3. Complete task")
print("4. Quit")
choice = input("Choose (1-4): ")

if choice == "1":
show_tasks(tasks)
elif choice == "2":
add_task(tasks)
elif choice == "3":
complete_task(tasks)
elif choice == "4":
print(f"Goodbye! You have {len(tasks)} task(s) left.")
break
else:
print("Invalid choice. Try again.")

main()

A few things worth noticing:

  • if not tasks: An empty list counts as False, so this reads as "if there are no tasks." Very Pythonic.
  • tasks.pop(number - 1) Users count from 1, Python counts from 0, so we subtract 1.
  • The functions change tasks without returning it. Remember the copy trap? When you pass a list into a function, the function gets the same list, not a copy. So add_task(tasks) updates the real list in main(). That's mutability working for you this time.

Practice Challenges

Beginner Level

  1. Favorite Movies: Make a list of 5 movies. Print the first one, the last one (using a negative index), and how many there are.
  2. Shopping List: Start with an empty list. Add 3 items with .append(), remove one, then print the list sorted.

Intermediate Level

  1. No Duplicates: Given [3, 1, 3, 2, 1, 5], build a new list with duplicates removed while keeping the original order. (Hint: loop + in + .append().)
  2. Second Largest: Find the second-largest number in a list without using .sort() or sorted().

Advanced Level

  1. To-Do List 2.0: Upgrade the mini project. Add an option to edit a task, and keep a second list of completed tasks you can view at the end.

Before You Go

Did lists click for you? Hit that 👏 clap button.

Built the To-Do app? Tell me in the comments what feature you added. Bonus points if it’s something I didn’t think of.

Coming up next: Dictionaries, where we stop storing things by position and start storing them by name. Your contact book is about to get phone numbers. 📱 Hit Follow so you don’t miss it.

See you in the next post! 🐍✨

Enjoying this series? Share it with a friend learning Python. Let’s all grow faster, together.

Check out the series so far:

  • Python in 2025: Why This Language Still Dominates
  • Variables and Data Types
  • Python Operators Decoded
  • Control Flow Mastery
  • Why Write Code Once When It Can Just… Repeat? (Loops)
  • Stop Copy-Pasting Your Code (Functions)

--

--

Ajay Narayan

Written by Ajay Narayan

Just a Python enthusiast sharing what I learn and discover along the way.