50 Python Interview Questions That Actually Get Asked — With Answers That Actually Help
I teach both Java and Python, and I run mock interview sessions on Topmate where candidates prep for backend and general developer roles. One thing I've noticed: most "Python interview question" articles online give you textbook definitions that fall apart the moment an interviewer asks a follow-up.
This post is different. I've organised 50 questions into the categories interviewers actually think in — from language fundamentals to the kind of production-thinking questions that separate mid-level candidates from senior ones. For each question, I've included the answer and the follow-up trap that catches most candidates.
How Python Actually Works — The Questions That Start Every Interview
Interviewers start here to gauge whether you've just used Python or whether you understand it. Getting these right with confidence sets the tone.
1. Is everything in Python an object?
Yes — integers, strings, functions, classes, modules, even None. Every object has an identity (id()), a type (type()), and a value. This isn't trivia — it's why you can pass functions as arguments, store them in dictionaries, and build decorators. When an interviewer asks this, they're checking whether you understand Python's object model or just its syntax.
2. What's the difference between is and ==?
== checks value equality. is checks whether two variables point to the same object in memory.
a = [1, 2] b = [1, 2] a == b # True — same values a is b # False — different objects
The trap: 256 is 256 returns True because CPython caches small integers (-5 to 256). Candidates who know the answer but not this gotcha get caught when asked "so does is always return False for equal values?"
3. How does variable assignment actually work?
Python variables are name tags pointing to objects, not boxes containing values. When you write a = 10; b = a, both reference the same integer object. Reassigning b = 20 makes b point to a new object — it doesn't change a. This is fundamental to understanding why mutable default arguments cause bugs.
4. What are truthy and falsy values?
Falsy: False, None, 0, 0.0, "", [], {}, set(). Everything else is truthy. Custom objects override this with __bool__ or __len__. The follow-up: "what does if my_list: actually check?" — it calls __bool__, which for lists delegates to __len__.
5. What is duck typing?
Python cares about what methods an object has, not its type. If it has a .read() method, it can be used wherever a file-like object is expected. This enables polymorphism without inheritance — no Java-style interfaces needed.
6. What happens when you import a module?
The module's code executes once, a module object is created, and it's cached in sys.modules. Common mistake I see: candidates don't realise top-level code runs at import time. If your module has a database connection at the top level, it fires during import — causing problems in testing and circular import scenarios.
7. What's Python's execution model?
Source code compiles to bytecode (.pyc files), then executes on the Python Virtual Machine. This applies to CPython — other implementations (PyPy, Jython) differ. The point: Python isn't purely interpreted, there's a compilation step.
8. What is late binding in closures?
Variables in closures are looked up when the inner function is called, not when it's defined:
funcs = [lambda: i for i in range(3)] [f() for f in funcs] # [2, 2, 2] — not [0, 1, 2]
Fix: lambda i=i: i captures the value at definition time. If a candidate explains this unprompted, they've hit this bug in real code.
Data Types and Mutability — Where Most Bugs Hide
9. Mutable vs immutable — and why it matters
Mutable: list, dict, set. Immutable: int, str, tuple, frozenset. Practical impact: immutable objects can be dict keys, and can be shared between threads safely. The interviewer isn't asking for a definition — they want to know you understand the consequences.
10. Why are strings immutable?
Hash safety (can be dict keys), memory sharing (string interning), and optimisation. Follow-up trap: "what happens when you concatenate strings in a loop?" — you create a new object each time, O(n²). Use ''.join() instead.
11. Shallow copy vs deep copy
import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) shallow[0].append(99) print(original) # [[1, 2, 99], [3, 4]] — original modified!
Shallow copies the outer structure but shares inner references. Deep copies everything recursively. I've seen candidates realise mid-session that a production bug they had was exactly this.
12. Why must dictionary keys be immutable?
Dicts use hash tables. If a key's hash changed after insertion, lookups would search the wrong bucket and fail silently. Lists can't be keys; tuples can (if contents are hashable).
13. List vs tuple — when to use which
Tuples: faster, less memory, hashable. Use for fixed data (coordinates, DB rows, return values). Lists: dynamic, use when you need add/remove. The signal: if the data shouldn't change, tuple communicates that intent.
14. What is __slots__?
Replaces the per-instance __dict__ with a fixed structure, reducing memory significantly. Matters when creating millions of objects. Trade-off: you lose dynamic attribute assignment.
Functions, Closures, and Decorators — The Mid-Interview Deep Dive
This is where interviews shift from "do you know Python?" to "do you understand Python?"
15. Why are mutable default arguments dangerous?
def add_item(item, items=[]): items.append(item) return items print(add_item("a")) # ["a"] print(add_item("b")) # ["a", "b"] — not ["b"]!
The default list is created once at function definition and shared across calls. Fix: use None as default, create a new list inside. About half the candidates I mock-interview get this wrong — even with 2+ years of Python.
16. What is a closure?
A function that captures variables from its enclosing scope, retaining them after the outer function returns. Closures are the mechanism behind decorators, factory functions, and callback patterns.
17. What is a decorator and how does it work?
A function that takes a function and returns a modified version. @my_decorator is sugar for func = my_decorator(func). Follow-up: "what happens to the original function's name?" — it gets replaced by the wrapper's, unless you use functools.wraps.
18. Generator vs iterator
An iterator implements __iter__() and __next__(). A generator is a convenient way to create iterators using yield. Generators are lazy — they produce values one at a time without holding the full sequence in memory. Use them for large files, database streams, or any data too big for a list.
19. When should you NOT use generators?
When you need random access, the length upfront, or to iterate multiple times. A generator is consumed after one pass. This is the follow-up that separates candidates who've memorised "generators are good for memory" from those who've actually used them.
20. Lambda — uses and limits
Single-expression anonymous functions. Good for short callbacks in sorted() or filter(). If your lambda is hard to read, use a named function. Readability beats conciseness.
21. First-class functions — what does this mean practically?
Functions can be assigned to variables, stored in data structures, passed as arguments, and returned from other functions. This makes decorators, callbacks, and strategy patterns possible without the ceremony Java requires.
OOP in Python
22. Multiple inheritance and MRO
Python supports multiple inheritance. Conflicts are resolved via the Method Resolution Order (C3 linearisation). Check it with MyClass.__mro__. The interview question: "what happens when two parent classes define the same method?" — the MRO decides deterministically.
23. Class variables vs instance variables
class User: roles = [] # class variable — shared! u1 = User() u2 = User() u1.roles.append("admin") print(u2.roles) # ["admin"] — u2 sees u1's change
If the class variable is mutable, mutations are visible to all instances. One of the most common Python OOP bugs.
24. Polymorphism in Python
Different objects responding to the same method. A list, str, and tuple all support len() — that's polymorphism, no shared base class needed (duck typing).
25. Abstract base classes
Defined using abc module with @abstractmethod. They enforce that subclasses implement certain methods — Python's closest equivalent to Java interfaces.
26. Composition vs inheritance
Composition ("has-a") is almost always preferable to inheritance ("is-a"). It's more flexible, easier to test, and avoids the fragile base class problem. Deep inheritance hierarchies in Python are usually a code smell.
27. __new__ vs __init__
__new__ creates the object (allocates memory). __init__ initialises it (sets attributes). Override __new__ for singletons, immutable types, or metaclass patterns — otherwise __init__ is sufficient.
28. Operator overloading
Define what +, ==, < mean for your objects via dunder methods (__add__, __eq__, __lt__). Key follow-up: if you override __eq__, also override __hash__ — or your objects won't behave correctly in sets and dicts.
Concurrency and the GIL — The Senior-Level Filter
This section separates candidates who've written Python scripts from those who've run Python in production.
29. What is the GIL?
A mutex in CPython ensuring only one thread executes Python bytecode at a time. It exists because CPython's reference counting isn't thread-safe. Impact: multi-threaded Python doesn't give true parallelism for CPU-bound work.
30. If the GIL prevents parallelism, why use threading?
I/O-bound work releases the GIL. When a thread waits for a network response or file read, other threads run. Threading is great for concurrent I/O (100 HTTP requests simultaneously) — just not for CPU-heavy computation. For CPU-bound work, use multiprocessing.
31. Threading vs multiprocessing vs asyncio
Threading: I/O-bound, moderate concurrency, simple to understand. Multiprocessing: CPU-bound, true parallelism, more memory overhead. Asyncio: high-concurrency I/O (thousands of connections), single thread with event loop, harder to debug.
32. What is a race condition?
Two threads read-modify-write shared data without synchronisation. The GIL doesn't prevent this — it only makes individual bytecode instructions atomic, not multi-step operations. counter += 1 involves read, increment, write — another thread can interleave.
33. What is asyncio?
An event-loop concurrency model. async def functions use await to pause during I/O, letting the event loop run other tasks. Single-threaded but highly concurrent for I/O. Key insight: asyncio doesn't make things faster — it makes your single thread busier by never letting it sit idle.
Memory, Performance, and Internals
34. How does garbage collection work?
CPython uses reference counting (immediate cleanup when count hits zero) plus a cyclic garbage collector for circular references (A→B→A). Understanding this matters for long-running services where memory leaks from reference cycles can accumulate.
35. What is weakref?
A reference that doesn't prevent garbage collection. Useful for caches — keep objects while they're in use, allow cleanup when memory is tight. If the object is collected, the weakref returns None.
36. How do you profile Python code?
cProfile for function-level CPU profiling, timeit for micro-benchmarks, memory_profiler for memory analysis, Py-Spy for production sampling. The interview answer isn't about naming tools — it's about demonstrating you've profiled something and acted on the results.
37. What is object interning?
CPython caches small integers (-5 to 256) and some strings. This is an implementation detail — don't write code that depends on it. It's why 256 is 256 is True but 257 is 257 may be False.
Production Python — The Questions That Reveal Real Experience
This is where I can tell whether someone has shipped Python to production or just used it for scripting.
38. print() vs proper logging
print() goes to stdout and disappears. Logging supports severity levels, structured output, file/remote destinations, and filtering. In production, print() is useless. If you're still using it for debugging in production code, that's a red flag.
39. Type hints
They don't affect runtime — Python ignores them. But they dramatically improve readability, IDE support, and catch bugs with mypy. Any serious Python codebase in 2026 uses type hints. Interviewers check whether you see them as overhead or as a tool.
40. Virtual environments
Isolated Python environments with independent packages. Without them, installing a package for one project can break another. Use venv or poetry. Every project should have one — no exceptions.
41. What is pyproject.toml?
The modern replacement for setup.py. Standard way to configure packaging, dependencies, and tool settings. If you're starting a new project in 2026 with setup.py, you're behind.
42. Why never use eval()?
It executes arbitrary Python code from a string. If user input reaches eval(), an attacker can do anything. Use json.loads(), ast.literal_eval(), or a proper parser instead.
43. How do you write secure Python code?
Validate all input. Avoid eval(), exec(), and pickle on untrusted data. Use parameterised queries for SQL. Keep dependencies updated. Apply least privilege. The answer isn't about listing tools — it's about showing security is part of your development process.
44. Designing Python services for scale
Async I/O (FastAPI + Uvicorn) for high concurrency. Stateless services for horizontal scaling. Background workers (Celery, RQ) for CPU-heavy tasks. Connection pooling. Aggressive caching. This is a system design question disguised as a Python question.
45. None vs False
None = absence of value. False = boolean value. None == False is False. Always use is None, never == None — because == can be overridden by custom classes, is cannot.
Quick-Fire Round
46. @staticmethod vs @classmethod
@staticmethod: no access to class or instance — just a function in the class namespace. @classmethod: receives cls as first argument, can access class attributes and serve as an alternative constructor.
47. Context managers
Objects with __enter__ and __exit__, used with with statements. Ensure cleanup (closing files, releasing locks) even on exceptions. Writing your own with contextlib.contextmanager is a sign of production fluency.
48. Monkey patching
Dynamically modifying a class or module at runtime. Occasionally useful for testing mocks. Dangerous in production — makes code unpredictable. If you're monkey-patching in production, there's almost certainly a better design.
49. How does exception handling work?
Exceptions propagate up the call stack until caught. Key point: use specific exception types, not bare except:. Bare except catches SystemExit and KeyboardInterrupt — that's a bug, not error handling.
50. What distinguishes a senior Python developer?
Understanding the runtime (GIL, GC, bytecode). Writing readable code, not clever code. Thinking about failure modes. Profiling before optimising. Designing for maintainability. They've hit real production bugs and learned from them — and that experience shows in every other answer.
How to Use This List
Don't memorise 50 answers. Go through each question and ask: can I explain this out loud, as if I'm teaching someone? If you can't, that's where you need to study — not by re-reading, but by writing code that demonstrates the concept and seeing it yourself.
If you want to test yourself under realistic conditions, book a mock interview session — I'll pick questions from this list and add follow-ups that test whether you truly understand or just memorised.
About the author: I'm Prashant Sharma — I teach Java and Python on YouTube and run interview prep courses on Udemy. For 1:1 mock interviews, book on Topmate.

Comments
Post a Comment