Freshers (0–2 years)
Practise this level-
1. What is the difference between a list and a tuple?
What they look for: Lists are mutable, tuples are not. Tuples can be dictionary keys and signal fixed data.
Recommended Answer:Lists are mutable (elements can be modified, appended, or deleted) and use square brackets []. Tuples are immutable (cannot be changed after creation), use parentheses (), and are memory-efficient. Because tuples are immutable, they are hashable and can be used as dictionary keys, whereas lists cannot.my_list = [1, 2, 3] my_list[0] = 99 # Valid my_tuple = (1, 2, 3) # my_tuple[0] = 99 -> TypeError: 'tuple' object does not support item assignment -
2. What are mutable and immutable types? Why does it matter?
What they look for: Mention the classic bug with a mutable default argument like def f(x=[]).
Recommended Answer:Mutable objects (list, dict, set) can change their state in-place without altering their memory address (id()). Immutable objects (int, float, str, tuple, frozenset) create a new object upon modification. In functions, mutable default arguments (e.g., def fn(arg=[])) persist across multiple calls, causing notorious bugs.# Safe function default argument def add_item(item, target_list=None): if target_list is None: target_list = [] target_list.append(item) return target_list -
3. What is the difference between a shallow copy and a deep copy?
What they look for: Shallow copies share nested objects; deep copies do not. Show an example with a nested list.
Recommended Answer:A shallow copy (copy.copy()) constructs a new compound object and inserts references to the original nested elements. A deep copy (copy.deepcopy()) recursively copies all nested objects, ensuring mutations to the copied hierarchy never affect the original data.import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 999 # Alters original[0][0] deep[0][0] = 111 # Original remains untouched -
4. What are *args and **kwargs?
What they look for: Variable positional and keyword arguments. Show where you have used them.
Recommended Answer:*args allows a function to accept any number of positional arguments as a tuple. **kwargs allows a function to accept variable keyword arguments as a dictionary. Useful for writing decorators, wrapper functions, and inheritance constructors.def log_call(*args, **kwargs): print('Positional:', args) # ('user', 101) print('Keyword:', kwargs) # {'role': 'admin'} log_call('user', 101, role='admin') -
5. What is a list comprehension? When should you not use one?
What they look for: A concise way to build lists. Avoid when the logic is complex enough to hurt readability.
Recommended Answer:List comprehensions provide a concise syntax to create new lists from existing iterables: [expr for item in iterable if condition]. They are faster than traditional for-loops due to C-level execution. Avoid using them when logic involves multi-line nested loops or side effects, as readability suffers.# Clean & fast comprehension even_squares = [x**2 for x in range(10) if x % 2 == 0] # [0, 4, 16, 36, 64] -
6. How do you handle exceptions in Python?
What they look for: try, except, else and finally. Catch specific exceptions rather than a bare except.
Recommended Answer:Handle exceptions using try, except, else, and finally blocks. Catch specific exception types rather than bare 'except:'. The 'else' block executes only if no exception occurred in the try block; 'finally' executes unconditionally (cleanup, closing DB connections).try: file = open('data.txt', 'r') data = file.read() except FileNotFoundError as err: logger.error('File not found: %s', err) else: process(data) finally: file.close() # Or use 'with open() as f:'
Mid-level (2–5 years)
Practise this level-
7. What are generators and why are they useful?
What they look for: Lazy iteration with yield; they save memory on large data. Give a file-reading or streaming example.
Recommended Answer:Generators are functions that produce items lazily using the 'yield' keyword instead of returning a complete list into memory. They maintain their execution state across calls, consuming minimal RAM even when processing gigabytes of log files or infinite series.def read_huge_file(file_path): with open(file_path, 'r') as f: for line in f: yield line.strip() # Memory used: Only 1 line at a time! -
8. What is a decorator? Write a simple one.
What they look for: A function that wraps another. Mention functools.wraps and a real use like timing or auth checks.
Recommended Answer:A decorator is a callable that takes another function as an argument, extends its behavior without modifying its source code, and returns the modified function. Widely used for timing, logging, authentication guards, and rate limiting.import time from functools import wraps def measure_time(func): @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(f'{func.__name__} took {time.time() - start:.4f}s') return result return wrapper @measure_time def compute(): time.sleep(0.1) -
9. What is the GIL and how does it affect multithreading?
What they look for: Only one thread runs Python bytecode at a time. Threads help for I/O; use multiprocessing for CPU-bound work.
Recommended Answer:The GIL (Global Interpreter Lock) is a mutex in CPython that ensures only one native OS thread executes Python bytecode at any given moment. It prevents race conditions in CPython's reference-counting memory manager. Consequently, multi-threading in Python speeds up I/O-bound tasks (network/file I/O), but does NOT provide parallel speedups for CPU-bound tasks. For true CPU parallelism, use multiprocessing or Celery. -
10. How does async/await work in Python?
What they look for: An event loop runs coroutines that yield at await points. Good for many concurrent I/O tasks.
Recommended Answer:Python's asyncio runs a single-threaded cooperative multitasking event loop. Coroutines defined with 'async def' pause at 'await' expressions, yielding control back to the event loop to service other tasks until I/O operations complete, achieving immense throughput for web APIs.import asyncio async def fetch_data(id): await asyncio.sleep(1) # Non-blocking I/O return f'Result {id}' async def main(): results = await asyncio.gather(fetch_data(1), fetch_data(2)) print(results) asyncio.run(main()) -
11. Django or FastAPI — when would you pick each?
What they look for: Django for full-featured apps with admin and ORM; FastAPI for fast, typed APIs. Justify with a project.
Recommended Answer:Choose Django when building full-featured web applications that need an integrated ORM, built-in admin dashboard, auth system, form handling, and templating out-of-the-box ('batteries included'). Choose FastAPI for lightweight, high-performance microservices, REST/GraphQL APIs, native async support, and automatic OpenAPI (Swagger) documentation via Pydantic.from fastapi import FastAPI app = FastAPI() @app.get('/health') async def health(): return {'status': 'healthy', 'service': 'MockVora API'} -
12. How do you manage dependencies and environments?
What they look for: Virtual environments with pinned versions — pip with requirements, Poetry or uv. Explain why pinning matters.
Recommended Answer:Use virtual environments (venv, uv, or poetry) to isolate project dependencies and prevent global Python package conflicts. Pin exact versions in requirements.txt or poetry.lock for deterministic and reproducible production builds.# Modern workflow python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt
Senior (5+ years)
Practise this level-
13. How does Python manage memory?
What they look for: Reference counting plus a cyclic garbage collector. Mention how reference cycles and large caches leak.
-
14. How would you speed up a slow Python service?
What they look for: Profile first, then fix the hot path: better algorithms, caching, async I/O, or moving heavy work to workers.
-
15. How do you design background jobs in a Python backend?
What they look for: Celery or similar with a broker, retries, idempotent tasks and monitoring.
-
16. How do you structure tests for a large Python codebase?
What they look for: pytest with fixtures, fast unit tests, fewer integration tests, and mocking only at boundaries.
-
17. What are type hints worth in a large codebase?
What they look for: Earlier bug detection with mypy or pyright, better editor support, and clearer interfaces between teams.
Frequently asked questions
Should I prepare Django or FastAPI?
Check the job description. If it does not say, know one well and understand the other at a high level.
Do Python interviews ask coding questions?
Yes, most include live coding — often a small problem on lists, dictionaries or strings, plus follow-ups on complexity.
Are data science Python interviews different?
Yes. They focus on pandas, NumPy, statistics and machine learning rather than web frameworks.