Top 50 Python Interview Questions with Answers

Top 50 Python Interview Questions with Answers

Master the most frequently asked Python interview questions and ace your next technical interview

Introduction

Python has become one of the most popular programming languages in the world, widely used in web development, data science, machine learning, automation, and more. Whether you're preparing for a job interview at a tech company or a startup, mastering Python fundamentals is essential.

This comprehensive guide covers the 50 most frequently asked Python interview questions, organized by topic for easy navigation. Each question includes a detailed answer with code examples where applicable.

How to Use This Guide: Read through all questions, but focus more on topics you're less confident about. Practice writing code for each concept to ensure you understand it deeply.

Python Basics (Q1-Q10)

Q1. What is Python? What are its key features?

Answer: Python is a high-level, interpreted, and general-purpose programming language. Key features:

  • Simple and Readable: Clean syntax, easy to learn
  • Interpreted: No compilation needed, runs directly
  • Dynamically Typed: No need to declare variable types
  • Object-Oriented: Supports OOP concepts
  • Extensive Libraries: Rich standard library and third-party packages
  • Cross-platform: Runs on Windows, Linux, macOS
  • Open Source: Free to use and modify

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

Answer: Key differences:

Python 2 Python 3
print is a statement print() is a function
Integer division returns int Integer division returns float
Unicode strings need 'u' prefix Strings are Unicode by default
xrange() for iteration range() returns iterator
raw_input() for input input() returns string
# Python 2
print "Hello"  # Statement
5 / 2  # Returns 2

# Python 3
print("Hello")  # Function
5 / 2  # Returns 2.5
5 // 2  # Returns 2 (integer division)
Note: Python 2 reached end of life in 2020. Always use Python 3 for new projects.

Q3. What are Python's built-in data types?

Answer: Python has several built-in data types:

  • Numbers: int, float, complex
  • Sequences: str, list, tuple, range
  • Mappings: dict
  • Sets: set, frozenset
  • Booleans: bool (True/False)
  • None: NoneType
# Numbers
x = 10  # int
y = 3.14  # float
z = 2 + 3j  # complex

# Sequences
name = "Python"  # str
numbers = [1, 2, 3]  # list
coordinates = (4, 5)  # tuple
r = range(5)  # range

# Mapping
person = {"name": "John", "age": 30}  # dict

# Sets
unique = {1, 2, 3}  # set
frozen = frozenset([1, 2, 3])  # frozenset

# Boolean
is_active = True  # bool

# None
value = None  # NoneType

Q4. What is the difference between list and tuple?

Answer:

List Tuple
Mutable (can be modified) Immutable (cannot be modified)
Defined with square brackets [] Defined with parentheses ()
More memory consumption Less memory consumption
Slower iteration Faster iteration
Methods: append(), extend(), remove() No methods to modify
# List - Mutable
my_list = [1, 2, 3]
my_list.append(4)  # [1, 2, 3, 4]
my_list[0] = 10  # [10, 2, 3, 4]

# Tuple - Immutable
my_tuple = (1, 2, 3)
# my_tuple[0] = 10  # Error! Cannot modify tuple
# my_tuple.append(4)  # Error! No append method

Q5. What is PEP 8?

Answer: PEP 8 is Python's official style guide. It provides conventions for writing readable Python code.

Key PEP 8 Guidelines:

  • Use 4 spaces for indentation (not tabs)
  • Maximum line length: 79 characters
  • Use blank lines to separate functions and classes
  • Use snake_case for function and variable names
  • Use PascalCase for class names
  • Use UPPER_CASE for constants
  • Import statements should be at the top
# Good PEP 8 style
def calculate_total(items):
    """Calculate total price of items."""
    total = 0
    for item in items:
        total += item.price
    return total

class ShoppingCart:
    MAX_ITEMS = 100  # Constant
    
    def __init__(self):
        self.items = []

Q6. What is the difference between == and is in Python?

Answer:

  • == (Equality): Compares the values of two objects
  • is (Identity): Compares if two variables point to the same object in memory
# == compares values
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)  # True (same values)

# is compares identity (memory location)
print(a is b)  # False (different objects)

# is returns True only if same object
c = a
print(a is c)  # True (same object)

# Special case: Small integers are cached
x = 256
y = 256
print(x is y)  # True (cached)

x = 257
y = 257
print(x is y)  # False (not cached)

Q7. What are Python decorators?

Answer: Decorators are functions that modify the behavior of other functions without changing their code. They use the @ symbol.

# Simple decorator
def my_decorator(func):
    def wrapper():
        print("Something before function")
        func()
        print("Something after function")
    return wrapper

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

say_hello()
# Output:
# Something before function
# Hello!
# Something after function

# Decorator with arguments
def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Python")  # Prints 3 times

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

Answer:

  • Shallow Copy: Creates a new object but references the same nested objects
  • Deep Copy: Creates a completely independent copy with its own nested objects
import copy

original = [[1, 2, 3], [4, 5, 6]]

# Shallow copy
shallow = copy.copy(original)
shallow[0][0] = 999
print(original)  # [[999, 2, 3], [4, 5, 6]] - Modified!
print(shallow)   # [[999, 2, 3], [4, 5, 6]]

# Deep copy
original = [[1, 2, 3], [4, 5, 6]]
deep = copy.deepcopy(original)
deep[0][0] = 999
print(original)  # [[1, 2, 3], [4, 5, 6]] - Not modified
print(deep)      # [[999, 2, 3], [4, 5, 6]]

Q9. What are Python generators?

Answer: Generators are functions that return an iterator. They use yield instead of return and generate values on-the-fly, saving memory.

# Generator function
def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

# Using generator
counter = count_up_to(5)
for num in counter:
    print(num)  # 1, 2, 3, 4, 5

# Generator expression
squares = (x**2 for x in range(5))
for square in squares:
    print(square)  # 0, 1, 4, 9, 16

# Memory efficient - doesn't store all values
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
for _ in range(10):
    print(next(fib))  # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34

Q10. What is the Global Interpreter Lock (GIL)?

Answer: GIL is a mutex that allows only one thread to execute Python bytecode at a time, even on multi-core systems.

Implications:

  • Python threads cannot run in parallel for CPU-bound tasks
  • GIL is released for I/O operations, so threads work well for I/O-bound tasks
  • For CPU-bound parallelism, use multiprocessing instead of threading
# Threading (affected by GIL) - good for I/O-bound
import threading
import time

def io_task():
    time.sleep(1)  # Simulates I/O operation

# Multiple threads can run concurrently for I/O
threads = [threading.Thread(target=io_task) for _ in range(5)]
for t in threads:
    t.start()
for t in threads:
    t.join()

# Multiprocessing (bypasses GIL) - good for CPU-bound
import multiprocessing

def cpu_task(n):
    return sum(i*i for i in range(n))

# Multiple processes run in parallel
with multiprocessing.Pool() as pool:
    results = pool.map(cpu_task, [1000000] * 4)

Data Structures (Q11-Q20)

Q11. What is the difference between list, tuple, set, and dictionary?

Answer:

Type Mutable Ordered Indexed Duplicates
list Yes Yes Yes Yes
tuple No Yes Yes Yes
set Yes No (Python 3.7+) No No
dict Yes Yes (Python 3.7+) Yes (by key) No (keys)

Q12. How do you remove duplicates from a list?

Answer: Multiple ways to remove duplicates:

# Method 1: Using set (loses order in Python < 3.7)
my_list = [1, 2, 2, 3, 4, 4, 5]
unique = list(set(my_list))  # [1, 2, 3, 4, 5]

# Method 2: Using dict.fromkeys() (preserves order)
unique = list(dict.fromkeys(my_list))  # [1, 2, 3, 4, 5]

# Method 3: Using list comprehension with seen set
seen = set()
unique = [x for x in my_list if not (x in seen or seen.add(x))]

# Method 4: Using OrderedDict (Python < 3.7)
from collections import OrderedDict
unique = list(OrderedDict.fromkeys(my_list))

Q13. What is list comprehension? Give examples.

Answer: List comprehension is a concise way to create lists.

# Basic syntax: [expression for item in iterable]

# Example 1: Squares
squares = [x**2 for x in range(5)]  # [0, 1, 4, 9, 16]

# Example 2: With condition
evens = [x for x in range(10) if x % 2 == 0]  # [0, 2, 4, 6, 8]

# Example 3: Nested
matrix = [[i*j for j in range(3)] for i in range(3)]
# [[0, 0, 0], [0, 1, 2], [0, 2, 4]]

# Example 4: With if-else
result = [x if x > 0 else 0 for x in [-1, 2, -3, 4]]  # [0, 2, 0, 4]

# Example 5: Flattening a list
nested = [[1, 2], [3, 4], [5, 6]]
flat = [item for sublist in nested for item in sublist]  # [1, 2, 3, 4, 5, 6]

Q14. What is dictionary comprehension?

Answer: Similar to list comprehension but creates dictionaries.

# Basic syntax: {key: value for item in iterable}

# Example 1: Squares dictionary
squares = {x: x**2 for x in range(5)}  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# Example 2: With condition
evens = {x: x*2 for x in range(10) if x % 2 == 0}

# Example 3: From two lists
keys = ['a', 'b', 'c']
values = [1, 2, 3]
mapping = {k: v for k, v in zip(keys, values)}  # {'a': 1, 'b': 2, 'c': 3}

# Example 4: Inverting dictionary
original = {'a': 1, 'b': 2, 'c': 3}
inverted = {v: k for k, v in original.items()}  # {1: 'a', 2: 'b', 3: 'c'}

Q15. How do you merge two dictionaries in Python?

Answer: Multiple ways to merge dictionaries:

# Method 1: Using ** operator (Python 3.5+)
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
merged = {**dict1, **dict2}  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

# Method 2: Using update()
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}  # 'b' will be overwritten
dict1.update(dict2)  # dict1 = {'a': 1, 'b': 3, 'c': 4}

# Method 3: Using | operator (Python 3.9+)
merged = dict1 | dict2

# Method 4: Using ChainMap
from collections import ChainMap
merged = dict(ChainMap(dict1, dict2))

Q16. What is the difference between append() and extend()?

Answer:

  • append(): Adds a single element to the end of the list
  • extend(): Adds all elements from an iterable to the end of the list
# append() - adds the whole object
my_list = [1, 2, 3]
my_list.append([4, 5])
print(my_list)  # [1, 2, 3, [4, 5]]

# extend() - adds elements from iterable
my_list = [1, 2, 3]
my_list.extend([4, 5])
print(my_list)  # [1, 2, 3, 4, 5]

# extend() with string
my_list = [1, 2]
my_list.extend("abc")
print(my_list)  # [1, 2, 'a', 'b', 'c']

Q17. What are *args and **kwargs?

Answer:

  • *args: Allows passing variable number of positional arguments (as tuple)
  • **kwargs: Allows passing variable number of keyword arguments (as dictionary)
# *args example
def sum_numbers(*args):
    return sum(args)

print(sum_numbers(1, 2, 3))  # 6
print(sum_numbers(1, 2, 3, 4, 5))  # 15

# **kwargs example
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="John", age=30, city="NYC")
# Output:
# name: John
# age: 30
# city: NYC

# Combined usage
def my_function(*args, **kwargs):
    print("Args:", args)
    print("Kwargs:", kwargs)

my_function(1, 2, 3, name="John", age=30)
# Args: (1, 2, 3)
# Kwargs: {'name': 'John', 'age': 30}

Q18. What is the difference between range() and xrange()?

Answer:

  • range() (Python 3): Returns a range object (iterator), memory efficient
  • xrange() (Python 2): Returns xrange object, memory efficient (removed in Python 3)
  • range() (Python 2): Returns a list, memory intensive
# Python 3 - range() returns iterator
r = range(5)
print(list(r))  # [0, 1, 2, 3, 4]
print(type(r))  # 

# Memory efficient - doesn't store all values
for i in range(1000000):  # Uses constant memory
    pass

# Python 2 (deprecated)
# range(5) returns [0, 1, 2, 3, 4] - list
# xrange(5) returns xrange object - iterator
Note: In Python 3, range() works like Python 2's xrange().

Q19. How do you sort a list in Python?

Answer: Multiple ways to sort:

# Method 1: sort() - modifies original list
my_list = [3, 1, 4, 1, 5, 9, 2, 6]
my_list.sort()
print(my_list)  # [1, 1, 2, 3, 4, 5, 6, 9]

# Method 2: sorted() - returns new sorted list
my_list = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_list = sorted(my_list)
print(sorted_list)  # [1, 1, 2, 3, 4, 5, 6, 9]
print(my_list)  # [3, 1, 4, 1, 5, 9, 2, 6] - unchanged

# Reverse sort
my_list.sort(reverse=True)  # [9, 6, 5, 4, 3, 2, 1, 1]

# Sort by key
students = [('John', 25), ('Jane', 22), ('Bob', 30)]
students.sort(key=lambda x: x[1])  # Sort by age
# [('Jane', 22), ('John', 25), ('Bob', 30)]

# Sort dictionary by value
my_dict = {'a': 3, 'b': 1, 'c': 2}
sorted_dict = dict(sorted(my_dict.items(), key=lambda x: x[1]))
# {'b': 1, 'c': 2, 'a': 3}

Q20. What is the difference between remove(), pop(), and del?

Answer:

Method Usage Returns
remove() Removes first occurrence of value None
pop() Removes element at index (default: last) Removed element
del Deletes element(s) by index/slice None
# remove() - removes by value
my_list = [1, 2, 3, 2, 4]
my_list.remove(2)  # Removes first 2
print(my_list)  # [1, 3, 2, 4]

# pop() - removes by index, returns value
my_list = [1, 2, 3, 4]
value = my_list.pop()  # Removes last element
print(value)  # 4
print(my_list)  # [1, 2, 3]

value = my_list.pop(0)  # Removes element at index 0
print(value)  # 1
print(my_list)  # [2, 3]

# del - deletes by index or slice
my_list = [1, 2, 3, 4, 5]
del my_list[0]  # Removes element at index 0
print(my_list)  # [2, 3, 4, 5]

del my_list[1:3]  # Removes slice
print(my_list)  # [2, 5]

Object-Oriented Programming (Q21-Q30)

Q21. What is the difference between class and instance variables?

Answer:

  • Class Variable: Shared by all instances, defined outside __init__
  • Instance Variable: Unique to each instance, defined in __init__
class Dog:
    # Class variable
    species = "Canine"
    count = 0
    
    def __init__(self, name):
        # Instance variable
        self.name = name
        Dog.count += 1

dog1 = Dog("Buddy")
dog2 = Dog("Max")

print(dog1.name)  # Buddy (instance variable)
print(dog2.name)  # Max (instance variable)
print(dog1.species)  # Canine (class variable)
print(dog2.species)  # Canine (class variable)
print(Dog.count)  # 2 (class variable)

Q22. What is __init__ method?

Answer: __init__ is a special method (constructor) that is automatically called when an object is created. It initializes the object's attributes.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print(f"{name} created")

person = Person("John", 30)
# Output: John created

print(person.name)  # John
print(person.age)   # 30

Q23. What is the difference between __str__ and __repr__?

Answer:

  • __str__: User-friendly string representation (for end users)
  • __repr__: Developer-friendly string representation (for debugging, should be unambiguous)
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __str__(self):
        return f"Point({self.x}, {self.y})"
    
    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"

p = Point(3, 4)
print(str(p))    # Point(3, 4) - user-friendly
print(repr(p))   # Point(x=3, y=4) - developer-friendly
print(p)         # Point(3, 4) - calls __str__

Q24. What is inheritance in Python?

Answer: Inheritance allows a class to inherit attributes and methods from another class.

# Parent class
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        return "Some sound"

# Child class
class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

dog = Dog("Buddy")
cat = Cat("Whiskers")

print(dog.speak())  # Buddy says Woof!
print(cat.speak())  # Whiskers says Meow!

Q25. What is method overriding?

Answer: Method overriding occurs when a child class provides a specific implementation of a method that is already defined in the parent class.

class Shape:
    def area(self):
        return 0

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):  # Overriding parent's area method
        return self.width * self.height

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):  # Overriding parent's area method
        return 3.14159 * self.radius ** 2

rect = Rectangle(5, 3)
circle = Circle(4)

print(rect.area())   # 15
print(circle.area()) # 50.26544

Q26. What is multiple inheritance?

Answer: Python supports multiple inheritance where a class can inherit from multiple parent classes.

class Flyable:
    def fly(self):
        return "Flying"

class Swimmable:
    def swim(self):
        return "Swimming"

class Duck(Flyable, Swimmable):
    def quack(self):
        return "Quack!"

duck = Duck()
print(duck.fly())    # Flying
print(duck.swim())   # Swimming
print(duck.quack())  # Quack!

# Method Resolution Order (MRO)
print(Duck.__mro__)  # Shows inheritance order

Q27. What is the difference between @staticmethod and @classmethod?

Answer:

@staticmethod @classmethod
No access to class or instance Receives class as first argument (cls)
Cannot modify class state Can modify class state
Called on class or instance Called on class or instance
class Math:
    pi = 3.14159
    
    @staticmethod
    def add(a, b):
        return a + b
    
    @classmethod
    def get_pi(cls):
        return cls.pi
    
    @classmethod
    def set_pi(cls, value):
        cls.pi = value

# Static method - no access to class/instance
result = Math.add(5, 3)  # 8

# Class method - access to class
print(Math.get_pi())  # 3.14159
Math.set_pi(3.14)
print(Math.get_pi())  # 3.14

Q28. What are magic methods (dunder methods)?

Answer: Magic methods are special methods with double underscores (__) that define how objects behave with built-in operations.

class Book:
    def __init__(self, title, pages):
        self.title = title
        self.pages = pages
    
    def __str__(self):
        return f"{self.title} ({self.pages} pages)"
    
    def __len__(self):
        return self.pages
    
    def __eq__(self, other):
        return self.pages == other.pages
    
    def __add__(self, other):
        return Book(f"{self.title} & {other.title}", 
                   self.pages + other.pages)

book1 = Book("Python", 300)
book2 = Book("Java", 250)

print(str(book1))        # Python (300 pages)
print(len(book1))        # 300
print(book1 == book2)    # False
combined = book1 + book2
print(combined)          # Python & Java (550 pages)

Q29. What is encapsulation in Python?

Answer: Encapsulation is the bundling of data and methods. Python uses naming conventions for access control:

  • Public: No prefix (default)
  • Protected: Single underscore (_)
  • Private: Double underscore (__)
class BankAccount:
    def __init__(self, balance):
        self.balance = balance          # Public
        self._account_number = "12345"  # Protected (convention)
        self.__pin = "0000"             # Private (name mangling)
    
    def get_balance(self):
        return self.balance
    
    def _validate(self):  # Protected method
        return True
    
    def __verify_pin(self):  # Private method
        return self.__pin == "0000"

account = BankAccount(1000)
print(account.balance)        # 1000 (accessible)
print(account._account_number) # 12345 (accessible but convention)
# print(account.__pin)         # Error! Name mangled to _BankAccount__pin
print(account._BankAccount__pin)  # 0000 (can access but shouldn't)

Q30. What is polymorphism in Python?

Answer: Polymorphism allows objects of different classes to be treated as objects of a common base class.

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "Woof!"

class Cat(Animal):
    def speak(self):
        return "Meow!"

class Duck(Animal):
    def speak(self):
        return "Quack!"

# Polymorphism - same interface, different implementations
animals = [Dog(), Cat(), Duck()]

for animal in animals:
    print(animal.speak())
# Output:
# Woof!
# Meow!
# Quack!

Advanced Topics (Q31-Q40)

Q31. What is a lambda function?

Answer: Lambda is an anonymous function defined with the lambda keyword. It can have any number of arguments but only one expression.

# Lambda syntax: lambda arguments: expression

# Regular function
def add(x, y):
    return x + y

# Lambda equivalent
add_lambda = lambda x, y: x + y

print(add(5, 3))        # 8
print(add_lambda(5, 3)) # 8

# Common use cases
# 1. With map()
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))  # [1, 4, 9, 16, 25]

# 2. With filter()
evens = list(filter(lambda x: x % 2 == 0, numbers))  # [2, 4]

# 3. With sorted()
students = [('John', 25), ('Jane', 22), ('Bob', 30)]
sorted_students = sorted(students, key=lambda x: x[1])  # Sort by age

Q32. What is the difference between map(), filter(), and reduce()?

Answer:

  • map(): Applies function to all items in iterable, returns map object
  • filter(): Filters items based on condition, returns filter object
  • reduce(): Applies function cumulatively, returns single value (from functools)
from functools import reduce

numbers = [1, 2, 3, 4, 5]

# map() - transform each element
squared = list(map(lambda x: x**2, numbers))  # [1, 4, 9, 16, 25]

# filter() - select elements
evens = list(filter(lambda x: x % 2 == 0, numbers))  # [2, 4]

# reduce() - accumulate to single value
sum_all = reduce(lambda x, y: x + y, numbers)  # 15
product = reduce(lambda x, y: x * y, numbers)  # 120

Q33. What are Python modules and packages?

Answer:

  • Module: A single Python file containing functions, classes, and variables
  • Package: A directory containing multiple modules and an __init__.py file
# Module: math_utils.py
def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

# Using module
import math_utils
result = math_utils.add(5, 3)

# Or
from math_utils import add, multiply
result = add(5, 3)

# Package structure:
# mypackage/
#   __init__.py
#   module1.py
#   module2.py

# Using package
from mypackage import module1
from mypackage.module2 import some_function

Q34. What is the difference between import and from import?

Answer:

# import - imports entire module
import math
result = math.sqrt(16)  # 4.0

# from import - imports specific items
from math import sqrt, pi
result = sqrt(16)  # 4.0
print(pi)  # 3.141592653589793

# from import * - imports all (not recommended)
from math import *
result = sqrt(16)  # Can use without math. prefix

# import as - aliasing
import numpy as np
import pandas as pd
Best Practice: Use specific imports (from module import function) instead of import * to avoid namespace pollution.

Q35. What is exception handling in Python?

Answer: Exception handling uses try-except blocks to handle errors gracefully.

# Basic exception handling
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")

# Multiple exceptions
try:
    value = int("abc")
    result = 10 / value
except ValueError:
    print("Invalid number!")
except ZeroDivisionError:
    print("Division by zero!")

# Exception with else and finally
try:
    file = open("data.txt", "r")
    content = file.read()
except FileNotFoundError:
    print("File not found!")
else:
    print("File read successfully!")
finally:
    print("This always executes")
    # file.close() would go here

Q36. What is the difference between finally and else in exception handling?

Answer:

  • else: Executes only if no exception occurs
  • finally: Always executes, regardless of exceptions
try:
    result = 10 / 2
except ZeroDivisionError:
    print("Error occurred")
else:
    print("No error - else block executes")  # This executes
finally:
    print("Finally always executes")  # This always executes

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Error occurred")  # This executes
else:
    print("No error")  # This doesn't execute
finally:
    print("Finally always executes")  # This always executes

Q37. What is the with statement?

Answer: The with statement ensures proper resource management (context management). It automatically handles setup and cleanup.

# File handling with 'with' statement
with open("file.txt", "r") as file:
    content = file.read()
    # File automatically closed when block exits

# Equivalent to:
file = open("file.txt", "r")
try:
    content = file.read()
finally:
    file.close()

# Custom context manager
class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
    
    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

with FileManager("data.txt", "w") as f:
    f.write("Hello, World!")

Q38. What are Python iterators and iterables?

Answer:

  • Iterable: Object that can be iterated over (has __iter__ method)
  • Iterator: Object that implements __iter__ and __next__ methods
# Custom iterator
class CountDown:
    def __init__(self, start):
        self.current = start
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        self.current -= 1
        return self.current + 1

# Using iterator
counter = CountDown(5)
for num in counter:
    print(num)  # 5, 4, 3, 2, 1

# Using next()
counter = CountDown(3)
print(next(counter))  # 3
print(next(counter))  # 2
print(next(counter))  # 1

Q39. What is the difference between list and generator?

Answer:

List Generator
Stores all values in memory Generates values on-the-fly
Can access by index Cannot access by index
Can iterate multiple times Can iterate only once
More memory consumption Memory efficient
# List - stores all values
my_list = [x**2 for x in range(1000000)]  # Uses memory

# Generator - generates on demand
my_gen = (x**2 for x in range(1000000))  # Memory efficient

# List can be accessed multiple times
my_list = [1, 2, 3]
for item in my_list:
    print(item)  # Works
for item in my_list:
    print(item)  # Works again

# Generator can be used only once
my_gen = (x for x in range(3))
for item in my_gen:
    print(item)  # 0, 1, 2
for item in my_gen:
    print(item)  # Nothing (exhausted)

Q40. What is the difference between threading and multiprocessing?

Answer:

Threading Multiprocessing
Shares memory space Separate memory space
Affected by GIL Bypasses GIL
Good for I/O-bound tasks Good for CPU-bound tasks
Lightweight Heavier (more overhead)
# Threading - I/O bound
import threading
import time

def io_task():
    time.sleep(1)  # Simulates I/O

threads = [threading.Thread(target=io_task) for _ in range(5)]
for t in threads:
    t.start()
for t in threads:
    t.join()

# Multiprocessing - CPU bound
import multiprocessing

def cpu_task(n):
    return sum(i*i for i in range(n))

with multiprocessing.Pool() as pool:
    results = pool.map(cpu_task, [1000000] * 4)

Libraries and Frameworks (Q41-Q50)

Q41. What is NumPy? Give an example.

Answer: NumPy is a library for numerical computing in Python, providing arrays and mathematical functions.

import numpy as np

# Creating arrays
arr = np.array([1, 2, 3, 4, 5])
matrix = np.array([[1, 2, 3], [4, 5, 6]])

# Array operations
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
result = arr1 + arr2  # [5, 7, 9]

# Mathematical operations
arr = np.array([1, 2, 3, 4, 5])
print(np.mean(arr))    # 3.0
print(np.max(arr))     # 5
print(np.sum(arr))     # 15

Q42. What is Pandas? Give an example.

Answer: Pandas is a library for data manipulation and analysis, providing DataFrame and Series structures.

import pandas as pd

# Creating DataFrame
data = {
    'Name': ['John', 'Jane', 'Bob'],
    'Age': [25, 30, 35],
    'City': ['NYC', 'LA', 'Chicago']
}
df = pd.DataFrame(data)

# Reading CSV
df = pd.read_csv('data.csv')

# Basic operations
print(df.head())        # First 5 rows
print(df.describe())    # Statistical summary
print(df['Age'].mean()) # Average age

Q43. What is the difference between Flask and Django?

Answer:

Flask Django
Microframework (minimal) Full-featured framework
Lightweight, flexible Batteries included
Good for small projects Good for large projects
More control More built-in features

Q44. What is a virtual environment?

Answer: A virtual environment is an isolated Python environment that allows you to install packages without affecting the system Python.

# Creating virtual environment
python -m venv myenv

# Activating (Windows)
myenv\Scripts\activate

# Activating (Linux/Mac)
source myenv/bin/activate

# Installing packages
pip install requests

# Deactivating
deactivate

# Requirements file
pip freeze > requirements.txt
pip install -r requirements.txt

Q45. What is pip?

Answer: pip is Python's package installer. It allows you to install and manage Python packages from PyPI (Python Package Index).

# Installing package
pip install package_name

# Installing specific version
pip install package_name==1.2.3

# Uninstalling
pip uninstall package_name

# Listing installed packages
pip list

# Showing package info
pip show package_name

# Upgrading
pip install --upgrade package_name

Q46. What is the difference between list and array in Python?

Answer:

  • List: Built-in, can hold different data types, flexible
  • Array (NumPy): From NumPy library, homogeneous data types, faster for numerical operations
# List - can hold different types
my_list = [1, 2, "three", 4.5]  # Valid

# NumPy array - homogeneous types
import numpy as np
my_array = np.array([1, 2, 3, 4])  # All integers
# my_array = np.array([1, 2, "three"])  # Converts to strings

# List operations are slower
my_list = [1, 2, 3, 4, 5]
result = [x * 2 for x in my_list]  # Slower

# Array operations are faster
my_array = np.array([1, 2, 3, 4, 5])
result = my_array * 2  # Faster, vectorized

Q47. What is the difference between .py and .pyc files?

Answer:

  • .py: Source code file (human-readable)
  • .pyc: Compiled bytecode file (created automatically by Python)
Note: .pyc files are created in __pycache__ directory to speed up program execution. Python uses them if the .py file hasn't changed.

Q48. What is __name__ == "__main__"?

Answer: This condition checks if the script is being run directly (not imported as a module).

# my_module.py
def greet(name):
    return f"Hello, {name}!"

if __name__ == "__main__":
    # This code runs only when script is executed directly
    print(greet("World"))
    print("This is the main program")

# When imported:
# import my_module
# The if block doesn't execute

# When run directly:
# python my_module.py
# The if block executes

Q49. What is the difference between == and is for None?

Answer: For None, both work the same, but is is preferred (PEP 8).

value = None

# Both work, but 'is' is preferred
if value == None:  # Works but not recommended
    print("None")

if value is None:  # Preferred (PEP 8)
    print("None")

# 'is' is faster and more Pythonic
# 'is' checks identity (same object)
# '==' checks equality (same value)

Q50. What are some best practices in Python?

Answer: Python best practices:

  • Follow PEP 8 style guide
  • Use meaningful variable names
  • Write docstrings for functions and classes
  • Use list comprehensions when appropriate
  • Handle exceptions properly
  • Use virtual environments
  • Don't use import *
  • Use is for None comparisons
  • Keep functions small and focused
  • Use type hints (Python 3.5+)

Interview Tips

Preparation Tips

  • Practice Coding: Write Python code daily on platforms like LeetCode, HackerRank
  • Understand Concepts: Don't just memorize, understand the "why" behind each concept
  • Know Your Libraries: Familiarize yourself with popular libraries (NumPy, Pandas, requests)
  • Practice Problem Solving: Solve Python-specific problems
  • Review Fundamentals: Strong basics are more important than advanced topics

During the Interview

  • Think Aloud: Explain your thought process
  • Ask Questions: Clarify requirements before coding
  • Write Clean Code: Follow PEP 8, use meaningful names
  • Handle Edge Cases: Consider None, empty lists, etc.
  • Test Your Code: Walk through examples

Common Mistakes to Avoid

  • Not understanding the difference between mutable and immutable types
  • Confusing list and tuple
  • Not handling exceptions
  • Using == instead of is for None
  • Not knowing about list comprehensions
  • Ignoring PEP 8 style guide
Previous
Next Post »

BOOK OF THE DAY