Stack in Python




A stack is a linear data structure that follows the LIFO (Last In, First Out) principle — meaning the last element added is the first one removed.

Stacks are one of the fundamental data structures in computer science, often used for:

Undo/redo functionality in editors
Browser back/forward navigation
Function call management in recursion
Expression evaluation (e.g., postfix/prefix parsing)

What is a Stack?

A stack stores elements in an ordered way, where elements are added and removed only from the top.

Operations on a stack:

Operation	Description	                         Example


push()	        Add an element to the top	        Add item
pop()	        Remove and return top element	        Remove last item
peek() / top()	Return top element without removing	View top
is_empty()	Check if stack is empty  	        Returns True/False

Method 1: Implementing Stack Using List

Python lists can easily act as stacks because they allow fast append (push) and pop operations from the end.


# Stack using Python list
stack = []

# Push elements
stack.append(10)
stack.append(20)
stack.append(30)

print("Stack after pushes:", stack)

# Pop element
popped = stack.pop()
print("Popped element:", popped)
print("Stack after pop:", stack)

# Peek (top element)
top = stack[-1]
print("Top element:", top)

Output:

 Stack after pushes: [10, 20, 30] 
Popped element: 30 
Stack after pop: [10, 20] 
Top element: 20 

✅ Using list is simple and fast for most stack use cases.
❌ But inserting/removing from the front (stack.insert(0, x)) is inefficient.

Method 2: Stack Implementation Using collections.deque

The deque (double-ended queue) from Python’s collections module is optimized for fast appends and pops from both ends — making it a better choice than list for stacks.

from collections import deque

# Create stack
stack = deque()

# Push items
stack.append('A')
stack.append('B')
stack.append('C')
print("Stack after pushes:", stack)

# Pop item
print("Popped:", stack.pop())
print("Stack after pop:", stack)

Output:

 Stack after pushes: deque(['A', 'B', 'C']) Popped: C Stack after pop: deque(['A', 'B']) 

✅ deque provides O(1) time for push and pop.
✅ Ideal for production-grade stack implementations.

Method 3: Stack Implementation Using Class (OOP Approach)

Let’s define a custom Stack class to handle operations cleanly.

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

def push(self, item):
    self.items.append(item)
    print(f"Pushed {item} -> {self.items}")

def pop(self):
    if not self.is_empty():
        removed = self.items.pop()
        print(f"Popped {removed} -> {self.items}")
        return removed
    else:
        print("Stack is empty!")

def peek(self):
    if not self.is_empty():
        return self.items[-1]
    return None

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

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

# Example usage
s = Stack()
s.push(10)
s.push(20)
s.push(30)
print("Top element:", s.peek())

s.pop()
s.pop()
print("Is stack empty?", s.is_empty())

Output:

 Pushed 10 -> [10] 
Pushed 20 -> [10, 20] 
Pushed 30 -> [10, 20, 30] 
Top element: 30 
Popped 30 -> [10, 20] 
Popped 20 -> [10] 
Is stack empty? False 

✅ Clear, object-oriented design
✅ Easy to maintain and expand (e.g., logging, limit size)
❌ Slightly more verbose for small tasks

Method 4: Stack Using queue.LifoQueue

The LifoQueue class from the queue module implements a thread-safe stack (LIFO Queue). It’s ideal for multi-threaded or synchronized environments.

from queue import LifoQueue

# Create stack with max size
stack = LifoQueue(maxsize=3)

# Push items

stack.put(10)
stack.put(20)
stack.put(30)

print("Full:", stack.full())

# Pop items

print("Popped:", stack.get())
print("Popped:", stack.get())
print("Empty:", stack.empty())

Output:

 Full: True Popped: 30 Popped: 20 Empty: False 

✅ Thread-safe (used in concurrent applications)
✅ Optional maxsize control
❌ Slightly slower due to synchronization overhead

Method 5: Stack Using Linked List (Custom Implementation)

Linked lists can be used to implement stacks when dynamic memory allocation is preferred.

class Node:
  def init(self, value):
     self.value = value
     self.next = None

class StackLinkedList:
  def init(self):
     self.top = None

def push(self, value):
    new_node = Node(value)
    new_node.next = self.top
    self.top = new_node
    print(f"Pushed {value}")

def pop(self):
    if self.top is None:
        print("Stack is empty")
        return
    removed = self.top.value
    self.top = self.top.next
    print(f"Popped {removed}")
    return removed

def peek(self):
    if self.top:
        return self.top.value
    print("Stack is empty")

def is_empty(self):
    return self.top is None

# Example usage
s = StackLinkedList()
s.push(10)
s.push(20)
s.push(30)
print("Top element:", s.peek())
s.pop()

Output:

 Pushed 10 Pushed 20 Pushed 30 Top element: 30 Popped 30 

✅ Memory-efficient for unknown/large data
✅ Useful for learning pointer-based stacks
❌ More complex to implement

Real-world Use Case: Balancing Parentheses Using Stack

Stacks are great for problems like checking if brackets are balanced in an expression.

def is_balanced(expression):
stack = []
pairs = {')': '(', ']': '[', '}': '{'}

for char in expression:
    if char in '([{':
        stack.append(char)
    elif char in ')]}':
        if not stack or stack[-1] != pairs[char]:
            return False
        stack.pop()

return not stack

# Test cases
print(is_balanced("(a + b) * [c - d]")) # True
print(is_balanced("(a + b * [c - d]")) # False

Output:

 True False 

When to Use a Stack?

Undo/Redo features (e.g., text editors)
Expression evaluation (postfix/prefix)
Function call management (recursion stack)
Syntax parsing and validation
Backtracking algorithms (e.g., maze solving, DFS)

FAQs — Stack in Python

What is a Stack in Python?

A stack in Python is a linear data structure that follows the LIFO (Last In, First Out) principle — the last element added is the first to be removed.

Stacks are commonly used in parsing, recursion, backtracking, and expression evaluation.

How to implement a Stack in Python using a list?

Lists are the simplest way to create a stack in Python using append() and pop() methods:

stack = []
stack.append(10)
stack.append(20)
print(stack.pop())  # Output: 20

Here, append() pushes elements and pop() removes the top element.

How to implement a Stack in Python using collections.deque?

deque (double-ended queue) from collections is more efficient for stack operations:

from collections import deque
stack = deque()
stack.append('a')
stack.append('b')
print(stack.pop())  # Output: b

deque provides O(1) time complexity for append and pop operations.

How to implement a Stack in Python using queue.LifoQueue?

The queue module’s LifoQueue class supports thread-safe stack operations:

from queue import LifoQueue
stack = LifoQueue()
stack.put(1)
stack.put(2)
print(stack.get())  # Output: 2

This is useful in multithreading scenarios.

What operations can be performed on a Stack in Python?
  • Push — Add an item to the top of the stack.
  • Pop — Remove the top item.
  • Peek / Top — View the top item without removing it.
  • isEmpty() — Check if the stack is empty.
  • Size() — Get the number of elements in the stack.
How to check if a Stack in Python is empty?

You can simply check the list length or boolean value:

if not stack:
    print("Stack is empty")

Empty lists or deques evaluate to False.

How to implement a custom Stack class in Python?

You can define your own stack structure using a class:

class Stack:
    def __init__(self):
        self.stack = []
    def push(self, item):
        self.stack.append(item)
    def pop(self):
        return self.stack.pop()
    def peek(self):
        return self.stack[-1]
    def is_empty(self):
        return len(self.stack) == 0

This provides a clear OOP-style stack implementation.

What is the time complexity of Stack operations in Python?

Using list or deque — both append() and pop() run in O(1) amortized time.

Accessing elements (like peek) is also O(1).

How to use Stack in Python for expression evaluation or parenthesis matching?

Stacks are ideal for checking balanced parentheses or evaluating expressions:

def is_balanced(expr):
    stack = []
    for ch in expr:
        if ch in "({[":
            stack.append(ch)
        elif ch in ")}]":
            if not stack or {')':'(',']':'[','}':'{' }[ch] != stack.pop():
                return False
    return not stack

This function returns True for balanced parentheses.

When should you use Stack in Python?

Use a stack in Python when you need to track function calls, undo operations, recursion, or nested structures. Typical use cases include expression parsing, DFS algorithms, and syntax validation.


Related Post