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.