Implementing Python Stack: Functions, Methods, Examples & More

Nitika Sharma Last Updated : 21 Feb, 2024
9 min read

Introduction

A stack push and pop in python is a core concept in programming and computer science. This article delves into implementing a Python stack, known for its Last-In-First-Out (LIFO) behavior, crucial for data management and algorithms. We explore essential principles, methods, and key considerations for efficient Python stack usage, important for all coders.

What is Stack in Python?

A stack is a linear data structure. It adheres to the Last-In-First-Out (LIFO) principle. Functioning as a collection of elements, the last item added is the first one to be removed. Some key operations associated with a stack in Python are as follows:

  • Push: Adding an element to the top of the push and pop in python.
  • Pop: Removing and returning the top element from the stack.
  • Peek: Viewing the top element without removing it.
  • Check for Empty: Verifying if the push and pop in python is devoid of elements.

Python stacks find utility in various applications, such as function call tracking, expression evaluation, and parsing algorithms.

How to Use Stack in Python?

A stack is a data structure that follows the Last-In-First-Out (LIFO) principle. This means the last element added to the stack will be the first one to be removed. It’s like a stack of books: you can only add or remove a book from the top of the stack.

In Python, we can use a list to represent a stack.

Creating a Stack

You can create a stack by initializing an empty list.

stack = []

Adding Elements to the Stack

We use the append() function to add elements to the top of the stack.

stack.append('A')
stack.append('B')
stack.append('C')

Now, our stack looks like this: ['A', 'B', 'C']. ‘C’ is at the top of the stack.

Removing Elements from the Stack

We use the pop() function to remove elements from the top of the stack.

top_element = stack.pop()

This will remove ‘C’ from the stack, and now our stack looks like this: ['A', 'B'].

Checking if the Stack is Empty

To check if the stack is empty, we can use the not operator.

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

And that’s it! You now know how to use a stack in Python. Remember, practice is key when learning new concepts in programming. So, try to incorporate the use of stacks in your next project! Happy coding! 🚀

Methods of Python Stack

Stacks in Python, like in many programming languages, come equipped with several fundamental methods and operations that facilitate the manipulation of data within this data structure. Let’s explore python stack methods:

  • push(item): This method adds an element (item) to the top of the stack.
stack.push(42)
  • pop(): The pop() method is employed to remove and retrieve the top element from the push and pop in python. This action reduces the amount of the stack by one. An error occurs if the stack is empty.
top_element = stack.pop()
  • peek(): For observing the top element of the stack without removing it, the peek() function is invaluable. It’s an excellent tool for inspecting the element at the stack’s pinnacle without altering the stack itself.
top_element = stack.peek()
  • is_empty(): This method determines whether the push and pop in python is empty. It returns True if the stack contains no elements and False otherwise.
if stack.is_empty():    
  print("The stack is empty.")
  • size(): To determine the number of elements presently residing in the stack, you can employ the size() method. It offers a straightforward means of gauging the stack’s length.
stack_size = stack.size()
  • clear(): When the need arises to remove all elements from the stack, effectively rendering it empty, the clear() function comes into play.
stack.clear()
  • not stack: In Python, you can employ the not operator to ascertain whether the push and pop in python contains any elements. This succinct approach allows you to discern if the stack is devoid of items.
if not stack:    
  print("The stack is empty.")

Also Read: Top 10 Uses of Python in the Real World with Examples

Functions of Python Stack

There are a number of built-in functions and standard library modules for a stack, including

  • List () and deque () Constructors: You can use the list() constructor or the deque () constructor from the collections module to create an empty stack.
stack_list = list()
stack_deque = deque()
  • list.extend(iterable) and deque.extend(iterable): These methods allow you to push multiple elements onto the stack at once by extending it with an iterable (e.g., a list or another stack).
stack_list.extend([1, 2, 3])
stack_deque.extend([4, 5, 6])
  • list.pop(index) and deque.popleft(): We’ve previously covered the pop() method for push and pop in python. Python lists also offer pop(index) to remove an element at a specific index. The deque.popleft() method efficiently removes and returns a deque’s leftmost (bottom) element, useful when simulating queue-like behavior with a deque-based stack.
stack_list.pop(1) # Remove and return the element at index 1
bottom_element = stack_deque.popleft()
  • heapq Module: The heapq module in Python provides functions to transform a list (or deque) into a min-heap. While it’s not a traditional stack operation, you can use a min-heap to implement certain stack-like behaviors, such as retrieving the smallest element.
import heapqstack 
= [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
heapq.heapify(stack) # Convert the list into a min-heap
smallest_element = heapq.heappop(stack) # Remove and return the smallest element
  • functools.lru_cache: This decorator from the functools module can be used to implement a cache with a stack-like behavior. It stores recently computed function results and discards the least recently used values when the cache reaches a specified size.
from functools import lru_cache
@lru_cache(maxsize=5)
def expensive_computation(n):
    # Expensive computation here
    return result

Implementation of Python Stack

  • Using Lists
# Creating an empty stack using a list
stack = []
# Pushing elements onto the stack
stack.append(1)
stack.append(2)
stack.append(3)
# Popping elements from the stack
top_element = stack.pop()

To construct an empty stack, we utilize a Python list in the code above. Then, we use the append() method to add items to the stack and the pop() method to remove them from it. However, lists are a flexible approach to designing a stack; remember that deque may be more effective for huge stacks.

  • Using deque (from the collections module)
from collections import deque
# Creating an empty stack using a deque
stack = deque()
# Pushing elements onto the stack
stack.append(1)
stack.append(2)
stack.append(3)
# Popping elements from the stack
top_element = stack.pop()

In this code, we use the deque data structure from the collections module to create a push and pop in python. Deques are optimized for fast append and pop operations from both ends, making them more efficient than lists for implementing stacks, especially when dealing with many elements.

  • Custom Stack Class

You can also create a custom stack class to encapsulate stack operations and provide a clean interface for working with stacks:

from collections import deque

class Stack:

   def __init__(self):
        self.stack = deque()
    def push(self, item):
        self.stack.append(item)
    def pop(self):
        if not self.is_empty():
            return self.stack.pop()
        else:
            raise IndexError("Pop from an empty stack")
    def peek(self):
        if not self.is_empty():
            return self.stack[-1]
        else:
            return None
    def is_empty(self):
        return not self.stack
    def size(self):
        return len(self.stack)

In the custom Stack class, we use a deque as the underlying data structure and provide methods for pushing, popping, peeking, checking if the stack is empty, and getting the size of the stack. This class provides a handy way to work with stacks in your Python code by abstracting the stack operations.

Deque vs List

FeatureDequeList
Data StructureDouble-ended queueDynamic array
EfficiencyOptimized for fast appends and pops from both ends.Slower for pops from the left side. Faster for pops from the right side.
Thread SafetyThread-safe with proper synchronization.Not inherently thread-safe; may require manual synchronization in multithreaded environments.
Memory EfficiencyMore memory-efficient, especially for large stacks.May consume more memory for large stacks due to dynamic array resizing.
Operationsappend(), pop(), and popleft() are efficient.append(), pop(), and pop(index) are available. pop(index) can be less efficient when popping from the left.
Random AccessNot suitable for random access.Supports random access by index, which may not be needed for stack operations.
Recommended Use CasesRecommended for most stack implementations, especially when efficiency is crucial.Suitable for small stacks or when additional list functionalities are required.

In summary, using a deque from the collections module is often the preferred choice for implementing stacks in Python due to its efficiency, thread safety, and memory efficiency. However, using a list can also be suitable for small stacks or when you need random access by index. Your choice depends on the specific requirements of your program.

Python Stacks and Threading

In computer science, stacks are fundamental data structures frequently used for Last-In-First-Out (LIFO) data management. It’s crucial to consider the effects of concurrency and multi-threading while utilizing stacks in Python. In this part, we’ll talk about threading interactions between Python stacks and the best ways to manage them in concurrent settings.

Thread Safety

Thread safety is a crucial consideration when working with data structures like stacks in a multi-threaded environment. The simultaneous access to shared data structures can result in race situations, data corruption, and other unexpected behavior in Python because threads share memory space.

Using Deque for Thread-Safe Stacks

One way to ensure thread safety when working with stacks in Python is to use the deque data structure from the collections module, designed to be thread-safe. Deques provide efficient append and pop operations from both ends, making them well-suited for stack implementations.

Here’s an example of using a deque-based stack in a multi-threaded Python program:

import threading
from collections import deque
# Create a deque-based stack
stack = deque()
# Define a function to push items onto the stack
def push_item(item):
    stack.append(item)
# Define a function to pop items from the stack
def pop_item():
    if stack:
        return stack.pop()
    else:
        print("Stack is empty.")
# Create multiple threads to manipulate the stack
thread1 = threading.Thread(target=push_item, args=(1,))
thread2 = threading.Thread(target=push_item, args=(2,))
thread3 = threading.Thread(target=pop_item)
thread4 = threading.Thread(target=pop_item)
# Start the threads
thread1.start()
thread2.start()
thread3.start()
thread4.start()
# Wait for all threads to finish
thread1.join()
thread2.join()
thread3.join()
thread4.join()

In this example, we use the threading module to concurrently create multiple threads that push and pop items from the deque-based stack. The deque’s thread safety ensures that these operations won’t interfere with each other, reducing the risk of data corruption.

Synchronization and Locks

Sometimes, you may need to use locks or synchronization mechanisms to coordinate access to a stack shared among multiple threads, especially when using a standard Python list as the underlying data structure. The threading module provides tools like Lock, Semaphore, and Condition to help you manage thread synchronization.

Here’s a simplified example of using a lock to protect a list-based stack:

import threading
# Create a list-based stack
stack = []
# Create a lock to protect the stack
stack_lock = threading.Lock()
# Define a function to push items onto the stack
def push_item(item):
    with stack_lock:
        stack.append(item)
# Define a function to pop items from the stack
def pop_item():
    with stack_lock:
        if stack:
            return stack.pop()
        else:
            print("Stack is empty.")
# Create multiple threads to manipulate the stack
thread1 = threading.Thread(target=push_item, args=(1,))
thread2 = threading.Thread(target=push_item, args=(2,))
thread3 = threading.Thread(target=pop_item)
thread4 = threading.Thread(target=pop_item)
# Start the threads
thread1.start()
thread2.start()
thread3.start()
thread4.start()
# Wait for all threads to finish
thread1.join()
thread2.join()
thread3.join()
thread4.join()

In this example, we use a Lock (stack_lock) to ensure that only one thread can access the stack at a time. This prevents concurrent access issues and ensures data consistency.

Which Implementation of Stack should one consider?

The choice of which implementation of a stack to consider in Python depends on your specific requirements and the characteristics of your program. Both lists and deques have advantages and are suitable for different use cases. Here’s a summary to help you decide which implementation to consider:

Deque (from the collections module)

  • Efficiency: Deques are optimized for fast appends and pops from both ends. They provide efficient push-and-pop operations, making them an excellent choice for most stack implementations, especially when dealing with many elements.
  • Thread Safety: Deques are inherently thread-safe, which means they can be used in multi-threaded environments with proper synchronization. A deque-based implementation is safer if you plan to work with stacks in concurrent programs.
  • Memory Efficiency: Deques are memory-efficient, particularly when dealing with large stacks. They consume less memory than lists because they are implemented as a double-ended queue.
  • Recommended Use Cases: Deques are recommended for most stack implementations, especially when efficiency and thread safety are crucial considerations. They are well-suited for scenarios where you must manage many elements and ensure data integrity in a multi-threaded environment.

List (Python built-in)

  • Efficiency: Lists can be slightly less efficient for pop operations, especially when popping from the left side. They are generally suitable for small stacks or when additional list functionalities (e.g., random access by index) are required.
  • Thread Safety: Lists are not inherently thread-safe. If you plan to use a list-based stack in a multi-threaded program, you must implement manual synchronization using locks or other mechanisms to avoid race conditions.
  • Memory Efficiency: Lists may consume more memory for large stacks because they are implemented as dynamic arrays. Consider using a deque if memory efficiency is a concern, especially for a large stack.
  • Recommended Use Cases: Lists are suitable for small stacks or random access by index. Using a list-based stack is a suitable option if your program is single-threaded and does not need thread safety.
  • Consider adopting a deque-based stack for most situations, especially when you need efficiency, memory efficiency, and thread safety. Deques are versatile and well-suited for a wide range of stack implementations. However, if your program is single-threaded and requires specific list functionalities, you can opt for a list-based stack. In multi-threaded programs, ensure proper synchronization when using lists to prevent concurrency issues.

Conclusion

In conclusion, mastering the implementation of stacks in Python is a fundamental skill for any programmer. Whether you choose to use lists or the deque data structure, understanding how to efficiently manage data in a Last-In-First-Out (LIFO) manner is essential. 

To further enhance your Python skills and broaden your programming horizons, consider enrolling in our FREE Python course. Explore the world of Python and unlock countless opportunities in data analysis, machine learning, and more. Start your learning journey today!

Frequently Asked Questions

Q1. What is a stack in Python?

A. A stack in Python is a linear data structure following Last-In-First-Out (LIFO) behavior, where the last element added is the first one removed. It’s used for various data management and algorithmic tasks.

Q2. Which stack uses Python?

A. Python provides several ways to implement a stack. One common approach is using lists or collections.deque as a basis to create a stack data structure.

Q3. Is Python list a stack or queue?

A. Python lists can be used as both stacks and queues, depending on how you implement them. By default, lists support stack-like operations, but you can also use them as queues by using methods like append for enqueue and pop(0) for dequeue.

Q4. Is there stack and queue in Python?

A. Yes, Python supports both stack and queue data structures. You can create a stack using lists or collections.deque, and for queues, you can use collections.deque or implement your own custom queue using lists.

Hello, I am Nitika, a tech-savvy Content Creator and Marketer. Creativity and learning new things come naturally to me. I have expertise in creating result-driven content strategies. I am well versed in SEO Management, Keyword Operations, Web Content Writing, Communication, Content Strategy, Editing, and Writing.

Responses From Readers

Clear

We use cookies essential for this site to function well. Please click to help us improve its usefulness with additional cookies. Learn about our use of cookies in our Privacy Policy & Cookies Policy.

Show details