Top Python Interview Questions & Answers

Table of Contents

1. What is Python, and why is it popular?

Python is a high-level, general-purpose programming language widely used for web development, software development, data science, artificial intelligence, automation, and more.

It is popular because of:

  • Simple and readable syntax – easy to learn and use.
  • Rich ecosystem of libraries – e.g., NumPy (numerical computing), Django (web development), TensorFlow (machine learning).
  • Large community support – constant updates, tutorials, and open-source contributions.
  • Cross-domain versatility – used in emerging fields like AI, data science, and automation.

These qualities make Python the preferred choice for startups and enterprises and a highly sought-after skill in today’s job market.

2. What is the difference between Python 2 and Python 3?

Python 2 is a legacy version, while Python 3 introduced significant improvements and is the modern standard.

Key differences:

  • Print statement: print "Hello" (Python 2) vs. print("Hello") (Python 3).
  • Strings: Python 2 uses ASCII by default; Python 3 uses Unicode.
  • Division: 5/2 → 2 in Python 2, but 2.5 in Python 3.
  • Exception syntax: Modernized in Python 3.
  • Library support: Most new libraries support Python 3 only.

Python 2 reached end-of-life in 2020, so Python 3 is the standard for modern development.

3. What is Python’s built-in types?

Python has several built-in types, broadly divided into immutable and mutable:

Immutable types:

  • int (integers)
  • float (floating-point numbers)
  • complex (complex numbers)
  • str (strings)
  • tuple (ordered collections)
  • bool (True/False)
  • frozenset (immutable sets)

Mutable types:

  • list (ordered collections)
  • dict (key-value pairs)
  • set (unordered unique elements)
  • bytearray (mutable sequence of bytes)
  • memoryview (exposes buffer interface)

Understanding these types helps developers write efficient and bug-free code.

4. What are Python decorators, and how are they used?

A decorator is a design pattern that allows you to add new functionality to a function or class without modifying its code.

  • Declared using the @decorator_name syntax above a function.
  • Useful for tasks like logging, authentication, measuring execution time, or code reuse.

Example:

def decorator(func):
    def wrapper():
        print("Before function")
        func()
        print("After function")
    return wrapper

@decorator
def say_hello():
    print("Hello!")

say_hello()

5. How does Python’s pass-by-object-reference work?

Python uses pass-by-object-reference:

  • When passing a variable to a function, a reference to the object is passed, not the actual object.
  • If the object is mutable (e.g., list, dict), changes inside the function affect the original object.
  • If the object is immutable (e.g., int, str, tuple), a new object is created for changes, leaving the original unchanged.

This behavior helps balance efficiency and flexibility in Python’s memory model.

6. What is the difference between a tuple and a list?

  • Tuple: Immutable, fixed collection of elements. Suitable for data that should not change (e.g., dictionary keys).
  • List: Mutable, flexible, can be modified (add, remove, update elements). Best for dynamic collections.

Performance-wise, tuples are slightly more efficient due to immutability.

7. How are errors and exceptions handled in Python?

Python uses the try/except/finally structure for exception handling:

try:
    x = 10 / 0
    except ZeroDivisionError:
    print("Division by zero is not allowed.")
finally:
    print("Execution finished.")
  • try code that may raise an exception.
  • except handles specific (or general) exceptions.
  • finally executes regardless of success or failure (useful for cleanup).
  • raise explicitly trigger an exception.

This mechanism ensures robust error handling and resource management.

8. What is PEP 8, and why is it important?

PEP 8 is the official style guide for Python code. It provides best practices for writing readable, consistent, and maintainable Python programs.

  • Why it matters: Without consistent guidelines, teams may use different coding styles, making the code harder to read and maintain. PEP 8 ensures everyone follows a common standard.
  • Key rules include:
    • Use 4 spaces per indentation level (no tabs).
    • Follow clear naming conventions for variables, functions, and classes.
    • Maintain proper whitespace usage around operators and after commas.
    • Organize imports logically (standard library → third-party → local).

Following PEP 8 makes code cleaner, easier to review, and less error-prone. Many companies enforce it as part of their coding standards, and tools like flake8 or pylint automatically check PEP 8 compliance.

9. Can Python be compiled, or is it only interpreted?

Python is primarily an interpreted language, but it also goes through a compilation step:

  • Normal execution flow:
    1. Source code (.py) is compiled into bytecode.
    2. Bytecode is executed by the Python Virtual Machine(PVM).
  • Compilation tools:
    1. Tools like PyInstaller, cx_Freeze, py2exe convert Python scripts into standalone executables (no interpreter required).
    2. Cython and Nuitka can compile Python into C/C++ for performance improvements.

10. What is the purpose of __init__.py in Python?

The __init__.py file serves two main purposes:

  • Package indicator:
    • It tells Python that a directory should be treated as a package.
    • This enables importing modules using import package_name.
  • Initialization code:
    • Code inside __init__.py runs when the package is imported.
    • Useful for setting up variables, exposing selected classes/functions, or running startup logic.

Since Python 3.3 (PEP 420), __init__.py is no longer strictly required (namespace packages). However, including it remains good practice for clarity, backward compatibility, and maintainability.

11. What is the difference between deep and shallow copy?

The difference lies in how nested objects are handled:

  • Shallow copy:
    • Creates a new object but only copies references to nested objects.
    • Changes in nested objects reflect in both copies.
    • Example: copy.copy()
  • Deep copy:
    • Creates a completely independent copy, including all nested objects.
    • Changes in the copy do not affect the original.
    • Example: copy.deepcopy()

Use shallow copy for lightweight duplication and deep copy when full independence is required.

12. What is the purpose of Python’s built-in function enumerate()?

The enumerate() function adds a counter(index) to an iterable while looping.

Example without enumerate():

fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits)):
    print(i, fruits[i])
With enumerate():
for i, fruit in enumerate(fruits):
    print(i, fruit)
  • Returns (index, value) pairs.
  • Makes code more readable and concise, while avoiding manual index tracking.

13. What are the differences between range and xrange in Python?

These existed in Python 2:

  • range (Python 2): Returns a list of numbers. Memory-intensive for large ranges.
  • xrange (Python 2): Returns an iterator that generates numbers on demand. Memory-efficient.

In Python 3:

  • Only range exists.
  • It behaves like xrange from Python 2 (lazy evaluation, memory-efficient).When migrating from Python 2 to 3, simply replace xrange with range.

14. What is Object-Oriented Programming, and how is it implemented in Python?

Object-Oriented Programming (OOP) is a paradigm that organizes code around objects (real-world entities) and classes (blueprints for objects). It promotes modularity, reusability, and clarity in software design.

OOP in Python:

  • Class definition: Use the class keyword to define a blueprint.
  • Objects: Instances created from classes.
  • Inheritance: A class can reuse and extend functionality from another.
  • Polymorphism: Different classes can define methods with the same name, but customized behavior.
  • Encapsulation: Bundles data (attributes) and behaviors (methods) together, with controlled access.

Since everything in Python (even numbers and strings) is an object, it provides a natural fit for OOP, making it easy to model real-world problems.

15. How does Python support encapsulation?

Encapsulation means hiding internal details of a class while exposing only what’s necessary. Python supports encapsulation through naming conventions and access control:

  • Public members: Accessible from anywhere.
  • Protected members (_var): A convention indicating "internal use only." Not enforced, but respected by developers.
  • Private members (__var): Trigger name mangling (_ClassName__var), making direct external access harder.

Encapsulation:

  • Keeps data safe from unintended modifications.
  • Groups related attributes and methods inside classes.
  • Promotes cleaner, modular, and maintainable code.

While Python doesn’t enforce strict access restrictions like Java or C++, it relies on developer discipline and conventions.

16. How can you explain inheritance and polymorphism in Python?

  • Inheritance:
    • Allows a class (child/derived class) to acquire attributes and methods of another class (parent/base class).
    • Encourages code reuse and avoids duplication.
    • Supports method overriding—child classes can redefine parent methods.
  • Polymorphism:
    • Means "many forms." Different classes can define the same method name but provide different behaviours.
    • Achieved via method overriding and duck typing in Python.
    • Example: Both Dog.speak() and Cat.speak() can exist, and you can call animal.speak() without knowing the exact class at runtime.

Together, inheritance and polymorphism enable flexibility, extensibility, and reusable code structures in Python applications.

17. How does Python support multiple inheritance?

Python allows multiple inheritance, meaning a class can inherit from more than one parent class.

Example:

class A:
    def greet(self): print("Hello from A")

class B:
    def greet(self): print("Hello from B")

class C(A, B):
    pass

c = C()
c.greet()  # Follows Method Resolution Order (MRO)
  • Challenge: If two parent classes have methods with the same name, ambiguity arises.
  • Solution: Python uses C3 Linearization (MRO – Method Resolution Order) to determine the order of class lookups.
    • You can view it with:
    • C.mro()

Multiple inheritance is powerful but should be used carefully to avoid complexity and conflicts.

18. How would you define and differentiate between instance, static, and class methods?

In Python, methods inside a class can be of three types:

  • Instance Methods:
    • Defined with self as the first parameter.
    • Operate on individual object instances.
    • Can access and modify object attributes.

Class Example:

def instance_method(self):
        print("This is an instance method")
  • Class Methods:
    • Defined using the @classmethod decorator.
    • Take cls (the class itself) as the first parameter.
    • Used for class-level operations and factory methods.

class Example:

    count = 0
    @classmethod
    def increment(cls):
        cls.count += 1
  • Static Methods:
    • Defined using the @staticmethod decorator.
    • Do not take self or cls.
    • Act like normal functions but live inside the class namespace.

class Example:

@staticmethod
    def utility():
        print("This is a static method")

Difference:

  • Instance methods → tied to objects.
  • Class methods → tied to the class.
  • Static methods → independent utilities inside a class.

19. What is a lambda function?

A lambda function is a small, anonymous function in Python.

  • Defined using the lambda keyword.
  • Can take multiple arguments but only one expression.
  • Expression is automatically returned.

Example:

add = lambda x, y: x + y
print(add(5, 3))  # Output: 8

Use cases: short, throwaway functions in map(), filter(), sorted(), etc.

20. What is the difference between a function and a method in Python?

  • Function:
    • Defined with def.
    • Independent block of code.
    • Not tied to any object or class.
def greet(name):
    return f"Hello {name}"
  • Method::
    • A function defined inside a class.
    • Operates on an object (needs self).
def say_hello(self):
        return "Hello"

Difference:

  • Functions → standalone.
  • Methods → always bound to class objects.

21. How can you share global variables across modules?

  • Create a separate config.py file:
    #config.py
    x = 10
    
  • Import and use it in another file:
    import config
    print(config.x)  # 10
    

Best practice: avoid too many globals → use constants or pass variables explicitly.

22. What are Python namespaces, and what is their purpose?

A namespace is a mapping between names and objects.

Types of namespaces:

  • Local → inside a function.
  • Global → at the module level.
  • Built-in → pre-defined (e.g., print, len).

Purpose: prevent naming conflicts.

x = 10  # global
def func():
    x = 5  # local

Ensures each identifier is unique in its context.

23. Explain Python’s scope resolution for variable names.

Python follows the LEGB rule for variable lookup:

  • Local → inside the current function.
  • Enclosing → variables from outer functions.
  • Global → module-level variables.
  • Built-in → Python reserved names (len, print).

Example:

x = "global"
def outer():
    x = "enclosing"
    def inner():
        x = "local"
        print(x)
    inner()
outer()  # local

Python searches in LEGB order until found.

24. Can you explain how to use the *args and **kwargs syntax?

  • *args → variable-length positional arguments (tuple).
  • **kwargs → variable-length keyword arguments (dict).

Example:

def example(*args, **kwargs):
print(args)    # tuple
    print(kwargs)  # dict

example(1, 2, 3, name="Alice", age=25)
# (1, 2, 3)
# {'name': 'Alice', 'age': 25}

Best practice: use *args for extra values, **kwargs for named options.

25. What is a metaclass in Python?

A metaclass in Python is a class of a class.

  • Just as a class defines how objects (instances) behave, a metaclass defines how classes behave.
  • By default, all classes in Python are instances of the built-in type metaclass.
  • You can think of it like this:
    • Object → instance of a Class.
    • Class → instance of a Metaclass.

Example (default behavior):

class MyClass:  
    pass  

print(type(MyClass))   # <class 'type'>
print(isinstance(MyClass, type))  # True

Custom Metaclass Example:

# Define a custom metaclass
class Meta(type):
    def __new__(cls, name, bases, dct):
        if "greet" not in dct:
            raise TypeError("Class must define a 'greet' method")
        return super().__new__(cls, name, bases, dct)

# This will work
class Person(metaclass=Meta):
    def greet(self):
        return "Hello"

# This will raise an error (no 'greet' method)
class Animal(metaclass=Meta):
    pass

Key Uses of Metaclasses:

  • Enforcing coding standards (e.g., ensuring subclasses define certain methods).
  • Automatically registering classes.
  • Adding/modifying class attributes dynamically.

In practice, metaclasses are rarely needed — they’re powerful but add complexity. They are mainly used in frameworks like Django and SQLAlchemy.

26. What is the proper way of writing a Python function to reverse a string?

The simplest and most Pythonic way is to use string slicing:

def reverse_string(s):
    return s[::-1]

print(reverse_string("hello"))  # Output: 'olleh'
  • s[::-1] creates a slice that starts from the end toward the first element, effectively reversing the string.
  • This method is concise, efficient, and leverages Python’s built-in slicing.

27. How do you check if a string is a palindrome in Python?

A palindrome reads the same forward and backward.

def is_palindrome(s):
    s = s.lower().replace(" ", "")   # normalize
    return s == s[::-1]

print(is_palindrome("mom"))       # True
print(is_palindrome("Race car"))  # True
  • Compare the string to its reverse.
  • Use .lower() and .replace() for case-insensitive, whitespace-tolerant checks.

28. How to implement a binary search algorithm in Python?

Binary search works only on sorted lists.

def binary_search(arr, target):
    low, high = 0, len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1

print(binary_search([1, 3, 5, 7, 9], 7))  # Output: 3
  • Time complexity: O(log n).
  • Returns index if found, else -1.

29. How to write a Python function to compute the factorial of a number?

Iterative approach:

def factorial_iter(n):
    result = 1
    for i in range(1, n+1):
        result *= i
    return result

Recursive approach:

def factorial_rec(n):
    if n == 0:
        return 1
    return n * factorial_rec(n - 1)
  • Recursion is elegant but may hit recursion depth limit for large n.
  • Iteration is safer for large numbers.

30. How to find the largest element in an array in Python?

arr = [10, 25, 5, 89, 45]
print(max(arr))   # Output: 89
  • Use built-in max().
  • For manual iteration:
def find_max(arr):
    maximum = arr[0]
    for num in arr:
        if num > maximum:
            maximum = num
    return maximum

31. How to write a Python function to sort a list of numbers in ascending order?

def sort_numbers(nums):
return sorted(nums)

print(sort_numbers([4, 2, 9, 1]))  # Output: [1, 2, 4, 9]
  • sorted() returns a new sorted list.
  • list.sort() sorts in place:
nums = [4, 2, 9, 1]
nums.sort()
print(nums)  # [1, 2, 4, 9]

32. How to find the intersection of two lists in Python?

list1 = [1, 2, 3, 4]
list2 = [3, 4, 5, 6]

intersection = list(set(list1) & set(list2))
print(intersection)  # [3, 4]
  • set.intersection() or & finds common elements.
  • Removes duplicates (since sets don’t allow them).

33. How to remove duplicates from a list in Python?

Quick method (unordered):

my_list = [1, 2, 2, 3, 4, 4, 5]
print(list(set(my_list)))  # [1, 2, 3, 4, 5]

Preserve order:

def remove_duplicates(lst):
    seen = []
    for item in lst:
        if item not in seen:
            seen.append(item)
    return seen

34. How to implement a stack in Python?

Using Python’s list:

stack = []

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

# Pop
print(stack.pop())  # 20
print(stack[-1])    # Peek → 10
Or wrap in a class:
class Stack:
    def __init__(self):
        self.items = []
    def push(self, item):
        self.items.append(item)
    def pop(self):
        return self.items.pop()
    def peek(self):
        return self.items[-1]
    def is_empty(self):
        return len(self.items) == 0

Stack follows LIFO (Last-In, First-Out).

35. How to write a Python program to read a file line by line and store it in a list?

To read a file line by line and store it in a list, use Python’s built-in open() function along with a list comprehension.

Example:

# Reading file line by line into a list
with open("example.txt", "r") as file:
    lines = [line.strip() for line in file]

print(lines)
  • The with statement ensures the file is closed automatically.
  • The strip() method removes newline characters \n.
  • Each line from the file becomes an element in the list.

36. How to write a Python script to merge two Python dictionaries?

There are multiple ways to merge dictionaries in Python:

  • Using update() (modifies the first dictionary):
    dict1 = {"a": 1, "b": 2}
    dict2 = {"b": 3, "c": 4}
    
    dict1.update(dict2)  # dict1 is modified
    print(dict1)  # {'a': 1, 'b': 3, 'c': 4}
    
  • Using dictionary unpacking (**) (Python 3.5+):
    dict1 = {"a": 1, "b": 2}
    dict2 = {"b": 3, "c": 4}
    
    merged_dict = {**dict1, **dict2}  # creates new dict
    print(merged_dict)  # {'a': 1, 'b': 3, 'c': 4}
    
  • Using the | operator (Python 3.9+):
    dict1 = {"a": 1, "b": 2}
    dict2 = {"b": 3, "c": 4}
    
    merged_dict = dict1 | dict2
    print(merged_dict)  # {'a': 1, 'b': 3, 'c': 4}
    

Choose based on whether you want in-place modification (update) or a new dictionary (** or |).

37. How to write a Python program to find the frequency of words in a string?

You can count word frequency using a dictionary or Python’s built-in collections.Counter.

Method 1: Using Dictionary

def word_frequency(text):
    words = text.split()
    freq = {}
    for word in words:
        word = word.lower()  # normalize case
        freq[word] = freq.get(word, 0) + 1
    return freq

text = "Python is great and Python is easy"
print(word_frequency(text))
# {'python': 2, 'is': 2, 'great': 1, 'and': 1, 'easy': 1}

Method 2: Using collections.Counter (shorter & efficient)

from collections import Counter

text = "Python is great and Python is easy"
freq = Counter(text.split())
print(freq)
# Counter({'Python': 2, 'is': 2, 'great': 1, 'and': 1, 'easy': 1})

Use Counter when you want quick frequency counts with extra utilities (like most_common).

38. How to write a Python program to find the second largest number in a list?

You can find the second largest number by removing duplicates, sorting the list, and picking the second last element.
Example:

def second_largest(nums):
    unique_nums = list(set(nums))  # remove duplicates
    if len(unique_nums) < 2:
        return "List must have at least two distinct numbers"
    unique_nums.sort()
    return unique_nums[-2]

print(second_largest([10, 20, 4, 45, 99]))  # 45
  • Handles duplicates
  • Includes edge case check

39. How to write a Python program to count the number of even and odd numbers in a list?

Loop through the list and use the modulus operator % to classify numbers as even or odd. Example:

def count_even_odd(numbers):
    even = odd = 0
    for num in numbers:
        if num % 2 == 0:
            even += 1
        else:
            odd += 1
    return even, odd

nums = [10, 21, 4, 45, 66, 93]
even, odd = count_even_odd(nums)
print("Even:", even, "Odd:", odd)

40. How to write a Python program to check whether a number is prime or not?

A prime number is greater than 1 and divisible only by 1 and itself. You only need to check divisibility up to the square root of the number.
Example:

import math

def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i == 0:
            return False
    return True

print(is_prime(29))  # True
print(is_prime(10))  # False

Optimized check using square root.

41. How to write a Python program to find common items between two lists without using intersection?

Use list comprehension to check membership of elements from one list in the other.
Example:

def common_items(list1, list2):
    return [item for item in list1 if item in list2]

list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
print(common_items(list1, list2))  # [4, 5]

Simple and works well for small lists.

42. What is the use of self in Python?

  • self represents the instance of a class.
  • It allows you to access attributes and methods of the class.
  • It binds instance variables with the arguments passed to the class.
  • Note: self is not a keyword in Python; it’s just a naming convention.

Example:

class Person:
    def __init__(self, name):
        self.name = name  # instance attribute

p = Person("Alice")
print(p.name)  # Output: Alice

43. What are global, protected, and private attributes in Python?

  • Global variables:
    • Defined in the global scope.
    • Accessed inside functions using the global keyword.
    x = 10  # global variable
    def func():
        global x
        x += 5
    
  • Protected attributes:
    • Prefixed with a single underscore _attribute.
    • Can be accessed outside the class but should not be modified directly.
    _name = "Alice"
    
  • Private attributes:
    • Prefixed with double underscore __attribute.
    • Cannot be accessed directly outside the class; raises AttributeError.
    class Employee:
        def __init__(self):
            self.__salary = 5000
    

44. What are modules and packages in Python?

  • Modules:
    • Python files with .py extension containing functions, classes, or variables.
    • Advantages:
      • Simplicity – focus on small part of the program.
      • Maintainability – reduces interdependency.
      • Reusability – reuse functions easily.
      • Scoping – separate namespace avoids conflicts.
    • Importing:
      import module_name
      from module_name import function_name
      
  • Packages:
    • Hierarchical structure of modules using folders.
    • Avoid module name conflicts.
    • Folder containing modules becomes a package.
    • Importing from a package:
      from package_name.module_name import function_name
      

45. What is an Interpreted Language?

  • An interpreted language executes its statements line by line.
  • Programs run directly from the source code without a separate compilation step.
  • Examples: Python, JavaScript, R, PHP, Ruby.

Key point:

  • Errors are detected during execution.
  • Easier for debugging compared to compiled languages.

46. What is a Dynamically Typed Language?

  • Typing refers to how a language checks the type of a variable.
  • In a strongly-typed language (e.g., Python), "1" + 2 gives a TypeError.
  • In a weakly-typed language (e.g., JavaScript), "1" + 2 outputs "12".

Type-checking stages:

  • Static – Checked before execution.
  • Dynamic – Checked during execution.
  • Python is dynamically typed because:
    • Type-checking happens on the fly while the program runs.
    • Variable types do not need to be declared explicitly.

Example:

x = 10      # x is integer
x = "Hello" # now x is string, no error

47. Explain split() and join() functions in Python

  • split(delimiter): Splits a string into a list of substrings based on the specified delimiter.
  • join(iterable): Joins elements of a list (or any iterable) into a single string using a specified delimiter.

Example:

string = "This is a string."
# Split string by space
string_list = string.split(' ')
print(string_list)  # Output: ['This', 'is', 'a', 'string.']

# Join list into string with space
print(' '.join(string_list))  # Output: This is a string.

48. What are Iterators in Python?

  • An iterator is an object used to iterate over iterable objects like lists, tuples, or strings.
  • Maintains state (current position) during iteration.
  • Key methods:
    • __iter__() – initializes the iterator.
    • __next__() – returns the next element; raises StopIteration at the end.
  • Iterators are self-iterable.

Example:

numbers = [1, 2, 3]
it = iter(numbers)
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# next(it) now raises Stop Iteration

49. How Python is Interpreted

  • Python is bytecode-interpreted:
    1. Source code (.py) is compiled to bytecode (.pyc).
    2. Bytecode is executed by the Python virtual machine (CPython) or JIT compiler (e.g., PyPy).
  • Python is not purely interpreted or compiled; the implementation defines this.

50. Difference between .py and .pyc files

Feature .py file .pyc file
Content Source code Compiled bytecode
Creation Written by programmer Generated after importing .py
Execution Compiled to bytecode first Executed directly by VM
Purpose Editable, human-readable Saves compilation time

Key point: .pyc files speed up execution by avoiding recompilation.

not found

Become a Master in Your Chosen Field by Earning Advanced Skills

Best Learning, More Earning

Proleed Education Private Limited

Proleed Academy is a brand of Proleed Education Pvt Ltd, committed to delivering high-quality IT training courses worldwide

 

Copyright © 2023 - Proleed Academy | All Rights Reserved.