← Back to Home

Python Interview Questions — What Senior Engineers Need to Know

Python interviews for senior roles focus on internals, not syntax. Expect deep questions about the GIL and its implications for concurrency, how CPython manages memory with reference counting and garbage collection, and the descriptor protocol that powers properties and classmethods.

These 28 questions target the gaps that separate mid-level Python developers from senior ones: metaclasses, import machinery, async/await internals, and the subtle differences between generators and coroutines. If you can explain these concepts to an interviewer, you’re demonstrating genuine depth.

All 28 Questions

GIL — What It Is and What It ProtectsSenior
What is Python's GIL, what does it protect, and what are its limitations?

The Global Interpreter Lock (GIL) is a mutex inside CPython that ensures only one thread executes Python bytecode at any given moment. It is not a feature of the Python language itself but an implementation detail of CPython, the reference implementation.

Read full answer →
ThreadPoolExecutor & ProcessPoolExecutorSenior
What is the difference between ThreadPoolExecutor and ProcessPoolExecutor?

Both ThreadPoolExecutor and ProcessPoolExecutor are part of Python's concurrent.futures module and provide a high-level interface for running callables asynchronously using a pool of workers. The key difference is the unit of concurrency and how Python's GIL affects them.

Read full answer →
Decorators — Under the HoodSenior
How do decorators work under the hood in Python?

A decorator in Python is a callable -- typically a function -- that takes a function as an argument and returns a new callable. The @decorator syntax is pure syntactic sugar. Writing @log_calls above a function definition is exactly equivalent to writing f = log_calls(f) after the def statement. …

Read full answer →
Generators & yieldMid
How do generators and the yield keyword work in Python?

A generator in Python is a special type of iterator. Unlike a regular function that computes its entire result and returns it, a generator produces values one at a time and suspends execution between each value. This lazy evaluation model enables processing of large or infinite sequences without …

Read full answer →
Context ManagersMid
What are context managers and how do you implement one?

A context manager is an object that defines a setup and teardown protocol for a block of code, ensuring cleanup happens reliably regardless of whether the block exits normally or via an exception. The with statement invokes this protocol.

Read full answer →
LEGB RuleEntry
What is the LEGB rule in Python's scope resolution?

LEGB is Python's name resolution order: when the interpreter encounters a variable name, it searches scopes in this sequence: Local → Enclosing → Global → Built-in. The first scope where the name is found wins.

Read full answer →
MRO, super(), Diamond ProblemSenior
Explain Python's MRO, how super() works, and the diamond problem.

Python's Method Resolution Order (MRO) determines which class's method is called when a name is looked up in an inheritance hierarchy. For single inheritance, this is trivial. For multiple inheritance, Python uses C3 linearization, an algorithm that produces a consistent, predictable linear order…

Read full answer →
@property — Getter, Setter, DeleterMid
How does @property work as a getter, setter, and deleter?

Python's `@property` decorator turns a method into a descriptor that's accessed like an attribute — `obj.name` instead of `obj.name()`. This lets you expose a clean attribute interface while executing code (validation, computation, lazy loading) on access or assignment.

Read full answer →
__slots__Senior
What are __slots__ and why would you use them?

By default, every Python instance stores its attributes in a per-instance dictionary (`__dict__`). This dictionary is flexible — you can add arbitrary attributes at runtime — but it carries significant overhead: a dict object requires ~200-300 bytes of baseline memory, plus the hash table's load …

Read full answer →
@classmethod vs @staticmethod vs @propertyMid
What is the difference between @classmethod, @staticmethod, and @property?

These three decorators are distinct tools that change how a method receives arguments and how it is invoked — understanding them requires understanding Python's descriptor protocol.

Read full answer →
is vs ==Entry
What is the difference between 'is' and '==' in Python?

In Python, `is` and `==` are fundamentally different operations that are often confused because they coincidentally produce the same result in common cases.

Read full answer →
Mutable Default ArgumentsEntry
Why are mutable default arguments dangerous in Python?

In Python, default argument values are evaluated **once** when the `def` statement is executed — not each time the function is called. For immutable defaults like integers, strings, or `None`, this is harmless because they cannot be modified in place. For mutable defaults like lists, dicts, or se…

Read full answer →
deepcopy vs Shallow CopyMid
What is the difference between deepcopy and shallow copy?

Copying in Python has three distinct levels: assignment, shallow copy, and deep copy. Choosing the wrong one causes aliasing bugs that are difficult to debug.

Read full answer →
__new__ vs __init__Senior
What is the difference between __new__ and __init__?

Object creation in Python is a two-step process mediated by `__new__` and `__init__`.

Read full answer →
Memory Management — GC, Ref CountingSenior
How does Python manage memory with garbage collection and reference counting?

CPython uses two complementary mechanisms for memory management: **reference counting** as the primary strategy and a **cyclic garbage collector** as a fallback for cyclic references that reference counting cannot handle.

Read full answer →
Decorator FactoryMid
What is a decorator factory and when would you use one?

A decorator is a function that takes a function and returns a modified function. A **decorator factory** is a function that takes arguments and *returns* a decorator. It adds one layer of nesting to allow the decorator to be parameterized.

Read full answer →
__getattr__ vs __getattribute__Senior
What is the difference between __getattr__ and __getattribute__?

`__getattribute__` and `__getattr__` are both attribute access hooks, but they differ fundamentally in when they are called and how dangerous they are to override.

Read full answer →
functools.partialMid
What is functools.partial and when would you use it?

`functools.partial` is a higher-order function that creates a new callable with some arguments of an existing function pre-filled (partially applied). Calling the resulting partial object supplies the remaining arguments.

Read full answer →
DefaultDict, OrderedDictMid
What are defaultdict and OrderedDict and when would you use them?

`defaultdict` and `OrderedDict` are both subclasses of `dict` in `collections`, each adding a specialized behavior on top of the standard dictionary.

Read full answer →
Duck TypingEntry
What is duck typing in Python?

Duck typing is a programming style where an object's suitability for a use is determined by the presence of the required methods and attributes, not by its class hierarchy. The name comes from the phrase: "If it walks like a duck and quacks like a duck, then it must be a duck."

Read full answer →
Monkey PatchingMid
What is monkey patching and what are the risks?

Monkey patching is the practice of dynamically modifying or replacing attributes, methods, or modules at runtime — without altering the original source code. In Python, because everything is an object and objects are mutable, this is syntactically trivial: you assign a new function to an attribut…

Read full answer →
MixinsMid
What are mixins and how do they differ from regular inheritance?

A mixin is a class that provides specific, reusable behavior intended to be 'mixed in' to other classes via multiple inheritance, without being instantiated directly or expressing an 'is-a' relationship. Mixins bundle a coherent set of methods that augment a target class, keeping concerns separat…

Read full answer →
Profiling — cProfileMid
How do you profile Python code with cProfile?

Profiling is the process of measuring where a program spends its time, so you can direct optimization efforts at the actual bottleneck rather than guessing. Python's built-in `cProfile` module is a deterministic profiler that instruments every function call and records call counts, total time, an…

Read full answer →
itertoolsMid
What are the most useful itertools functions and when do you use them?

The itertools module provides building blocks for efficient looping in Python, operating lazily so they never materialize full sequences in memory.

Read full answer →
Pytest — Fixtures, Mocking, PatchingMid
How do pytest fixtures, mocking, and patching work?

**Fixtures** are functions decorated with `@pytest.fixture` that pytest injects into test functions by parameter name. They handle setup and teardown via yield: code before yield runs before the test, code after yield runs after it regardless of outcome. Fixtures have scopes — function (default, …

Read full answer →
Code Coverage / Static AnalysisEntry
What are code coverage and static analysis tools and why are they useful?

**Code coverage** quantifies how much of your source code is exercised by a test suite. The standard Python tool is `coverage.py`, typically invoked via `pytest --cov`. It instruments the bytecode to track which lines execute. The report shows line coverage (percentage of lines hit) and optionall…

Read full answer →
Package Management — Poetry, PyPI, virtualenvMid
How do Poetry, PyPI, and virtualenv relate in Python package management?

**PyPI** (Python Package Index) is the public registry of Python packages. When you run `pip install requests`, pip fetches the package from PyPI. Packages are uploaded to PyPI by maintainers in wheel or source-distribution format.

Read full answer →
Python Modules, Packages, __init__.pyEntry
What is the difference between modules and packages? What does __init__.py do?

A **module** in Python is any single `.py` file. When you write `import utils`, Python finds `utils.py` on the module search path (`sys.path`) and executes it, caching the result in `sys.modules`. The module's top-level names become attributes on the imported object.

Read full answer →

How to Prepare

Focus on understanding concepts deeply enough to explain them in your own words. For each topic, practice articulating the trade-offs and real-world applications — interviewers care about practical judgment, not textbook definitions.

Related Topics

  • CS Fundamentals Interview Questions
  • Frameworks Interview Questions
  • Technical Interview Practice

Test Your Knowledge

Take a free AI-graded assessment across multiple domains. No signup required.

Start Free Assessment
GrindQuestionsAITechnical interview assessment
TermsPrivacyAbout