A stack is a last-in-first-out (LIFO) data structure — the last item you add is the first one you remove. It shows up everywhere in real code: undo history in an editor, the call stack behind every function call, and backtracking algorithms like maze solvers. Python doesn't have a dedicated stack type, but a plain list already supports everything a stack needs.

The key insight is that a list's append() and pop() methods both operate on the end of the list, and both run in O(1) time — which is exactly the "push onto the top" and "pop off the top" behavior a stack needs.

Program to Implement a Stack Using a List in Python

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if self.is_empty():
            raise IndexError("pop from an empty stack")
        return self.items.pop()

    def peek(self):
        if self.is_empty():
            raise IndexError("peek from an empty stack")
        return self.items[-1]

    def is_empty(self):
        return len(self.items) == 0

    def size(self):
        return len(self.items)


# Demo
stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)

print(f"Top of stack: {stack.peek()}")
print(f"Popped: {stack.pop()}")
print(f"Popped: {stack.pop()}")
print(f"Stack size: {stack.size()}")

Output:

Top of stack: 30
Popped: 30
Popped: 20
Stack size: 1

Notice push and pop both act on self.items[-1], the end of the list — never the front. If you accidentally used self.items.pop(0) or insert(0, item) instead, it would still "work" logically, but every call would be O(n) instead of O(1), since Python has to shift every remaining element over. For a queue (first-in-first-out) rather than a stack, you'd want collections.deque instead, which keeps O(1) operations at both ends.

The is_empty() guard in pop() and peek() matters in practice — calling .pop() on an empty Python list raises IndexError: pop from empty list anyway, but raising it explicitly with a clearer message makes debugging a lot easier when this class is buried inside a bigger program.