You already know the Python list. You write scores = [10, 20, 30] and it just works. So why would anyone build a different kind of list by hand? Because in a job interview, someone will ask you to, and because building one teaches you how data structures actually work under the surface.
A linked list is a chain of small boxes, where each box holds a value and a link to the next box. There's no single block of memory like a normal list has. Instead the boxes sit anywhere, and each one points to where the next one lives. In this lesson you'll build the whole thing from scratch: one node, then a three-node chain by hand, then a small class that inserts, deletes, and searches.
What a linked list actually is
Picture a treasure hunt. Each clue tells you one thing plus where to find the next clue. The last clue says "you're done, there's nothing after this."
A linked list works the same way. Each box is called a node. A node holds two things: a value, and a link to the next node. That link is just a reference to another node. The last node's link points to None, and that None is how you know you've reached the end.

The first node has a special name. It's the head. If you have the head, you can reach every other node by following the links one at a time. Lose the head and the whole chain is gone, because nothing else tells you where the list starts.
How it differs from a normal Python list
A Python list keeps all its items in one block of memory, side by side. Because they sit together in order, Python can jump straight to any position. Ask for scores[1] and you get it instantly, no matter how long the list is.
scores = [10, 20, 30]
print(scores[1])
scores.insert(0, 5)
print(scores)
# Output:
# 20
# [5, 10, 20, 30]
A linked list is different. Its nodes are scattered around memory, not lined up. There's no position number you can jump to. To reach the third node, you start at the head and follow two links. To reach the hundredth, you follow ninety-nine links. This is the trade you're making.

So a normal list is fast at reaching a position and slower when you add to the front (every item has to shift over). A linked list is slow at reaching a position and fast at adding to the front. Different jobs, different tool.
Why anyone uses one
Here's the one thing a linked list is genuinely good at. To add a new item at the very front, you make one new node, point it at the old head, and call it the new head. That's it. Nothing else moves.
In a normal Python list, inserting at the front means every existing item slides one spot to the right to make room. With three items that's nothing. With a million items, that's a million moves, every single time you insert at the front. The linked list changes one link instead.
The honest second reason is interviews. Linked lists are one of the most common data structure topics in coding interviews. Reversing a linked list, finding its middle, detecting a loop: these questions come up again and again. So even though you'll rarely build one at work, you learn it well because you'll be asked about it.
The Node class, three lines
A node needs to hold two things, so you build a small class for it. You haven't seen classes yet in this course, so here's the short version: a class bundles some data and functions together into one thing, and the __init__ method runs automatically when you create one, setting up its starting values. A later lesson covers classes properly. For now, just read it line by line.
class Node:
def __init__(self, value):
self.value = value
self.next = None
Line one names the class Node. Line two says "when you make a new node, you hand it a value." Line three stores that value on the node as self.value. Line four sets self.next to None, because a brand new node isn't linked to anything yet. That's the whole node: a value and a link that starts empty.
Linking three nodes by hand
Before any helper class, let's build a chain the slow way so you can see the links. Make three nodes, then join them yourself:
class Node:
def __init__(self, value):
self.value = value
self.next = None
first = Node(10)
second = Node(20)
third = Node(30)
first.next = second
second.next = third
print(first.value)
print(first.next.value)
print(first.next.next.value)
print(first.next.next.next)
# Output:
# 10
# 20
# 30
# None
Read those last four prints slowly. first.value is 10. first.next is the second node, so first.next.value is 20. first.next.next is the third node, so its value is 30. And first.next.next.next is None, because you never gave the third node a next. That None is the end of the chain.
Walking the chain with a loop
Chaining .next.next.next by hand doesn't scale. To visit every node, you use a while loop with a pointer that walks forward. Start the pointer at the head, print the value, then move the pointer to the next node. Stop when the pointer reaches None.
class Node:
def __init__(self, value):
self.value = value
self.next = None
first = Node(10)
first.next = Node(20)
first.next.next = Node(30)
node = first
while node is not None:
print(node.value)
node = node.next
# Output:
# 10
# 20
# 30

The line node = node.next is the heart of every linked list loop. It moves the pointer one step down the chain. Forget it and the loop never ends, because node stays on the same box forever. We'll come back to that mistake later.
A small LinkedList class
Doing this by hand every time is painful, so wrap it in a class. The LinkedList only needs to remember one thing: its head. Everything else it finds by walking. Here it is with three methods, add to front, add to end, and print.
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, value):
new_node = Node(value)
if self.head is None:
self.head = new_node
return
node = self.head
while node.next is not None:
node = node.next
node.next = new_node
def insert_at_front(self, value):
new_node = Node(value)
new_node.next = self.head
self.head = new_node
def display(self):
node = self.head
while node is not None:
print(node.value, end=" -> ")
node = node.next
print("None")
chain = LinkedList()
chain.append(20)
chain.append(30)
chain.insert_at_front(10)
chain.display()
# Output:
# 10 -> 20 -> 30 -> None
Look at insert_at_front. It's three short lines and it never touches the rest of the chain. Make the node, point it at the current head, make it the new head. That's the cheap-insert advantage in code.

The append method has more work to do. To add at the end, it walks all the way to the last node (the one whose next is None) and links the new node there. That walk is why adding to the end of a linked list is slower than adding to the front.
Deleting a node by value
Deleting is where people slip up, so go slowly. To remove a node, you don't erase it. You relink around it. Find the node just before the one you want gone, and point its next at the node after the target. The target now has nothing pointing to it, so Python cleans it up.
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, value):
new_node = Node(value)
if self.head is None:
self.head = new_node
return
node = self.head
while node.next is not None:
node = node.next
node.next = new_node
def delete(self, value):
node = self.head
if node is not None and node.value == value:
self.head = node.next
return
while node is not None and node.next is not None:
if node.next.value == value:
node.next = node.next.next
return
node = node.next
def display(self):
node = self.head
while node is not None:
print(node.value, end=" -> ")
node = node.next
print("None")
chain = LinkedList()
chain.append(10)
chain.append(20)
chain.append(30)
chain.delete(20)
chain.display()
# Output:
# 10 -> 30 -> None

The first if handles a special case: what if the node you're deleting is the head itself? Then there's nothing before it, so you just move the head forward to the next node. The loop handles every other case by looking one step ahead with node.next.value.
Searching the chain
Searching is the same walk you already know, with a check inside. Start at the head, compare each value, and stop the moment you find a match.
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, value):
new_node = Node(value)
if self.head is None:
self.head = new_node
return
node = self.head
while node.next is not None:
node = node.next
node.next = new_node
def search(self, value):
node = self.head
while node is not None:
if node.value == value:
return True
node = node.next
return False
chain = LinkedList()
chain.append(10)
chain.append(20)
chain.append(30)
print(chain.search(20))
print(chain.search(99))
# Output:
# True
# False
The method returns a boolean: True as soon as it finds the value, False if the walk reaches None without a match. There's no shortcut here. You have to check nodes one by one, because a linked list can't jump to a position.
Singly and doubly linked lists
Everything above is a singly linked list: each node points forward only. You can walk from head to end, but never backward.
A doubly linked list gives each node a second link that points to the node before it. Now you can walk both directions, and deleting is easier because a node already knows who comes before it. The cost is more memory (two links per node instead of one) and more links to keep correct on every insert and delete. You won't write the full code here, just know the shape.

Linked list versus Python list
Here's the whole comparison in one place. Read it once and the trade-off sticks.
| What you're doing | Python list | Linked list |
|---|---|---|
| Get the item at a position | Instant, jumps straight there | Slow, walks from the head |
| Add to the front | Slow, shifts every item over | Fast, changes one link |
| Add to the end | Fast | Slow, walks to the last node |
| Memory | One tidy block | Extra link stored per node |
| When to use | Almost always | Interviews, and heavy front inserts |
For everyday Python, use a list. It's faster for the things you actually do, it's built in, and the code is shorter. You learn the linked list to pass interviews and to understand how structures work, not because you'll reach for one on a normal day. That's the honest answer, and anyone who tells you different is selling something.
Practice exercises
Try each one before you read the solution. Everything you need is above.
Build a three-node chain by hand
Make three nodes holding "Mon", "Tue", "Wed" and link them, then print all three values.
# Solution
class Node:
def __init__(self, value):
self.value = value
self.next = None
a = Node("Mon")
b = Node("Tue")
c = Node("Wed")
a.next = b
b.next = c
print(a.value, a.next.value, a.next.next.value)
# Output: Mon Tue Wed
Count the nodes
Given a three-node chain, count how many nodes it has by walking it.
# Solution
class Node:
def __init__(self, value):
self.value = value
self.next = None
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
count = 0
node = head
while node is not None:
count += 1
node = node.next
print(count)
# Output: 3
Insert at the front
Start with a chain of 20 then 30. Add 10 to the front so the chain reads 10, 20, 30.
# Solution
class Node:
def __init__(self, value):
self.value = value
self.next = None
head = Node(20)
head.next = Node(30)
new_node = Node(10)
new_node.next = head
head = new_node
node = head
while node is not None:
print(node.value, end=" ")
node = node.next
print()
# Output: 10 20 30
Find a value
Walk a chain of 5, 15, 25 and print True if 15 is in it.
# Solution
class Node:
def __init__(self, value):
self.value = value
self.next = None
head = Node(5)
head.next = Node(15)
head.next.next = Node(25)
target = 15
found = False
node = head
while node is not None:
if node.value == target:
found = True
break
node = node.next
print(found)
# Output: True
Common mistakes
- Losing the head reference. If you move your loop pointer with
self.head = self.head.next, you throw away the start of the list. Walk with a separate variable (node = self.head) and leaveheadalone. - Forgetting
node = node.nextin the loop. Without it the pointer never moves, so thewhileloop runs forever on the same node. This is the most common infinite loop with linked lists. - Not handling the empty list. If
self.headisNone, code that readsself.head.valuecrashes with anAttributeError. Check for the empty case first. - Relinking in the wrong order when deleting. If you overwrite a link before you've saved the node it pointed to, you cut off the rest of the chain. Point past the target first, then let the target go.
Frequently asked questions
What is a linked list in Python?
A chain of small objects called nodes. Each node holds a value and a link to the next node, and the last link is None. You build it yourself from a small Node class, because Python has no built-in linked list type.
Does Python have a built-in linked list?
No. You build your own with a Node class, or you use collections.deque, which is a doubly linked list under the surface and gives you fast adds and removes at both ends.
What's the difference between a linked list and a list?
A Python list stores items in one block and can jump to any position instantly. A linked list scatters its nodes and follows links, so it's slower to reach a position but faster to add at the front.
What is a node?
One box in the chain. It holds a value and a link (next) to the following node. In code it's a tiny class with two attributes.
What is the head of a linked list?
The first node. It's the only node you keep a direct reference to. From the head you can reach every other node by following links. Lose it and you lose the list.
Why does the last node point to None?
None marks the end. When your walking pointer reaches None, there are no more nodes, so your loop knows to stop.
When should I use a linked list?
Rarely in everyday Python, a list is better for most work. Use one to answer interview questions, or when your program does a lot of inserting and removing at the front and you want that to stay fast.
What's the difference between singly and doubly linked?
A singly linked node points forward only. A doubly linked node also points backward, so you can walk both ways and delete more easily, at the cost of extra memory and more links to maintain.
Key takeaways
- A linked list is a chain of nodes, where each node holds a value and a link to the next one, and
Nonemarks the end. - The head is the first node and your only handle on the list. Walk the chain with
node = node.nextuntil you hitNone. - Adding to the front is one link change, which is the real advantage. Reaching a position means walking from the head, which is the real cost.
- A
Nodeclass needs just a value and anext. ALinkedListclass needs just a head, plus methods to insert, delete, and search. - In day-to-day Python you'll almost always use a normal list. You learn linked lists for interviews and to understand how data structures work.
The most common place a linked list shows up in real Python is hidden inside collections.deque, which powers fast stacks and queues. If you want to see that in action instead of building the links yourself, read our guide to stacks and queues in Python.

By Kaustubh Saini 