Interview Preparation

Python Interview Questions & Answers for 2026

Curated questions covering core concepts, practical scenarios, and tradeoffs — suitable for fresher, 2-year, and 5-year experience levels.

Q1. What is the GIL in Python and how does it affect multithreading?

The Global Interpreter Lock is a mutex in CPython that allows only one thread to execute Python bytecode at a time. This means Python threads cannot run truly in parallel on multiple CPU cores for CPU-bound tasks. However threads are still useful for I/O-bound tasks because the GIL is released during blocking I/O operations like network calls or file reads. For CPU-bound parallelism use the multiprocessing module which creates separate processes with separate GILs. Python 3.13 is introducing per-interpreter GIL as an experimental option.

Q2. What are Python generators and when should you use them?

Generators are functions that use yield instead of return and produce values lazily — one at a time on demand. They save memory when working with large datasets because they do not compute all values upfront. A generator function returns a generator object; each call to next() resumes execution until the next yield. Use generators for data pipelines, reading large files line by line, infinite sequences, and streaming data processing. Generator expressions (x for x in range(n)) are the concise form for simple cases.

Q3. Explain Python decorators and write a simple example.

A decorator is a function that takes another function as input, adds behaviour, and returns a new function. They use the @syntax as syntactic sugar. Example: @timing_decorator before a function is equivalent to func = timing_decorator(func). Common real-world uses: logging, authentication checks, caching with functools.lru_cache, rate limiting, and retry logic. When writing decorators use functools.wraps to preserve the original function's name and docstring, otherwise introspection tools see the wrapper instead.

Q4. What is the difference between a list, tuple, and set in Python?

Lists are ordered, mutable sequences — use them when order matters and items change. Tuples are ordered, immutable sequences — use them for fixed data like coordinates or function return values; they are slightly faster and can be dictionary keys. Sets are unordered, mutable collections of unique items — use them for membership testing (O(1) vs O(n) for lists) and removing duplicates. Frozensets are immutable sets usable as dict keys. In interviews interviewers often ask for time complexity: list search O(n), set/dict lookup O(1) on average.

Q5. How does Python manage memory and what is garbage collection?

Python uses reference counting as its primary memory management mechanism — when an object's reference count drops to zero it is immediately deallocated. To handle circular references (A references B, B references A) Python also has a cyclic garbage collector that runs periodically to detect and collect these cycles. The gc module lets you inspect and control this. Memory leaks in Python are rare but can happen with global caches, circular references in C extensions, or long-lived closures holding references to large objects.

Q6. What are context managers and how do you create a custom one?

Context managers handle setup and teardown logic using the with statement, ensuring resources are properly released even if an exception occurs. Built-in examples: with open() for files, with threading.Lock() for locks. To create a custom context manager implement __enter__ and __exit__ on a class, or use the @contextlib.contextmanager decorator with a generator that yields once. The with statement calls __enter__ on entry and __exit__ on exit, passing exception information if one occurred.

Q7. What is the difference between shallow copy and deep copy in Python?

A shallow copy creates a new object but populates it with references to the same child objects as the original. Modifying a nested object in the copy also affects the original. A deep copy creates a new object and recursively copies all nested objects, producing a fully independent copy. Use copy.copy() for shallow and copy.deepcopy() for deep copies. Shallow copies are faster and sufficient when the object contains only immutable items (strings, numbers). Deep copies are needed when objects contain mutable nested structures like lists of dicts.

Q8. How does async/await work in Python and how does it differ from threading?

Python's async/await uses an event loop (asyncio) to run coroutines concurrently in a single thread. When a coroutine hits an await on an I/O operation it suspends and the event loop runs another coroutine. This is cooperative multitasking — coroutines yield control voluntarily. Threading uses OS-managed context switching between threads. Async is more efficient for high-concurrency I/O-bound workloads (thousands of simultaneous HTTP calls) with lower overhead. Threading is easier for existing synchronous code and works with blocking libraries. Use asyncio + aiohttp or FastAPI for async web APIs.

Practice these questions with AI

Use our Mock Interview tool to answer questions and receive instant AI scoring and model answers.

Start Mock InterviewGenerate Custom Questions