Python Interview Questions and Answers
A complete list of 795+ Python interview questions and answers, organized by topic. Click any question to jump straight to its detailed answer with code examples.
14 topics 795 questions
Python Fundamentals
Mutability & Data Types
- Which Python types are mutable and which are immutable?
- What is the mutable default argument trap?
- What is the difference between `is` and `==`?
- What is the difference between a shallow and a deep copy?
- Can a tuple contain mutable objects?
- Why can't you use a list as a dictionary key?
- What does the id() function tell you?
- Why does `is` sometimes work for equal integers?
- What is string interning in Python?
- What happens when you use += on a list inside a tuple?
- Does slicing a list create a copy?
- Is Python pass-by-value or pass-by-reference?
- How does deepcopy handle circular references?
- When is using `is` instead of `==` a bug?
- How do you make a custom class hashable?
- What is a frozen dataclass?
- Why are strings immutable in Python?
- What is the difference between a tuple and a list?
- What happens if you modify a list while iterating over it?
- What does the del statement do?
- What is the difference between rebinding and mutating?
- Why is a mutable class attribute shared across instances?
- What is the trap with [[]] * 3?
- What is a namedtuple and when do you use it?
- What do the global and nonlocal keywords do?
- What are the ways to copy a list or dict?
- Why check for None with `is` rather than ==?
- Why must set elements be hashable?
- Do comprehensions leak their loop variable?
- How does tuple unpacking enable swapping variables?
- What is the trap with shallow-copying nested structures?
- What is a frozenset?
- What is the relationship between __eq__ and __hash__?
Variables, Scope & the LEGB Rule
- What is the LEGB rule?
- What is the difference between `global` and `nonlocal`?
- Why does assigning to a name make it local and cause UnboundLocalError?
- Why do closures in a loop all capture the same value?
- How does name shadowing work between module and function scope?
- Do comprehensions have their own scope?
- How can you inspect what a closure has captured?
- In which scope are default argument values evaluated?
- What do the `globals()` and `locals()` functions return?
- Can a nested function read an enclosing variable without `nonlocal`?
- Why can't methods see class-body variables directly?
- What does `del` do to a name's scope?
- What happens if you assign to a built-in name at module level?
- What is a "free variable" and how does it differ from a global?
- Why does patching a global affect already-defined functions but rebinding a local doesn't?
Numbers & Operators
- What are Python's built-in numeric types?
- How do `/`, `//`, and `%` behave, especially with negatives?
- Why don't Python integers overflow?
- Why is 0.1 + 0.2 not exactly 0.3?
- What are Python's bitwise operators?
- What do `divmod` and `**` do?
- How does `bool` relate to `int` in arithmetic?
- How do `int()`, `float()`, and `round()` differ in converting numbers?
- How do chained comparisons like `a < b < c` work?
- Is `x += 1` the same as `x = x + 1`?
- When should you use the `math` module instead of operators?
- What is special about `float('nan')`?
- Why does `a is b` sometimes work for equal integers?
- How do you work with complex numbers?
- How do you format numbers for display?
- What do underscores in numeric literals do?
Strings & String Formatting
- What is the difference between f-strings, .format(), and % formatting?
- What is the difference between str and bytes?
- What are the common string methods like split, strip, and join?
- Why use join instead of += to build a string in a loop?
- What is a raw string and when do you use it?
- How does the format spec mini-language work (padding, :.2f)?
- What does it mean that strings are immutable?
- How do you check for substrings and find their positions?
- What string methods test or change case and content type?
- Why might two visually identical strings compare unequal?
- How does string slicing work, including negative steps?
- What do `!r`, `!s`, and `=` do inside f-strings?
- How do triple-quoted strings and implicit concatenation work?
- How do you efficiently replace or delete many characters at once?
- When would you use `partition` instead of `split`?
Truthiness & Type Conversion
- Which values are falsy in Python?
- How does Python decide whether a custom object is truthy?
- How do explicit type conversions like int(), str(), and list() work?
- Are empty containers and None falsy?
- What do `and` and `or` actually return?
- Why use `is None` instead of `== None`?
- Why can `if x:` be a bug when you mean `if x is not None:`?
- How does `bool()` convert numbers and strings?
- How do `any()` and `all()` use truthiness?
- When does Python convert numeric types implicitly?
- Does `if a == b == c` compare truthiness or values?
- How do you convert between number bases?
- What surprises happen when converting between containers?
- What is the difference between `str()` and `repr()`?
- How do you convert between characters and their code points?
- Is `float('nan')` truthy or falsy?
Python Data Structures
Lists & Slicing
- What is the difference between a Python list and an array?
- How does list slicing work, including negative steps?
- What is the difference between append, extend, and insert?
- Are list comprehensions faster than equivalent for loops?
- What is the difference between list.sort() and sorted()?
- What is the trap with [[]] * 3?
- Why shouldn't you remove items from a list while iterating it?
- How do you copy a list, and what is shallow vs deep?
- How does negative indexing work?
- How do you loop with both index and value?
- Can you use a list as a stack and a queue?
- What is the time complexity of `x in my_list`?
- How does starred unpacking work with lists?
- How do you sort a list of objects by a field?
- How do you keep a list sorted efficiently as you insert?
Tuples & Named Tuples
- What is the difference between a tuple and a list, and when should you use each?
- What are tuple packing and unpacking, and how do you write a single-element tuple?
- Is a tuple's immutability deep? Can a tuple contain mutable objects?
- What is a namedtuple and how does collections.namedtuple compare to typing.NamedTuple?
- Why can a tuple be used as a dictionary key when a list cannot?
- Do tuples require parentheses?
- Are tuples faster or lighter than lists?
- What methods do tuples have?
- What extra features does a namedtuple add?
- When do you choose a namedtuple vs a dataclass?
- How does tuple unpacking enable swapping without a temp variable?
- How do *args and tuples relate?
- What happens when you concatenate or multiply tuples?
- How are tuples compared?
- Why is (5) not a tuple but (5,) is?
Dictionaries
- Are Python dictionaries ordered?
- What is the difference between d[key], d.get(key), and d.setdefault()?
- What are the ways to merge two dictionaries?
- What do keys(), values(), and items() return, and what is a view object?
- Why must dictionary keys be hashable, and why are lookups O(1)?
- What is a dict comprehension?
- What are the ways to remove a key from a dict?
- Can you modify a dict while iterating over it?
- When does setdefault shine over get, and what is its catch?
- Why can't you use a list as a dict key but can use a tuple?
- What does dict.fromkeys do, and what is its shared-default trap?
- How does a Python dict handle hash collisions internally?
- Are dict view objects live?
- What do the | and |= dict operators do?
- For counting, when do you choose Counter vs defaultdict(int) vs get?
- How does a dict decide two keys are the same?
Sets & Frozensets
- What are the main set operations in Python?
- Why is membership testing faster in a set than a list?
- How do you remove duplicates from a list using a set?
- What is the difference between add, discard, and remove on a set?
- What is a frozenset and when do you need one?
- What is a set comprehension?
- How do you create an empty set?
- What types can go into a set?
- Are sets ordered or indexable?
- How do you test subset and superset relationships?
- What is the difference between | and |= (and friends) on sets?
- What does symmetric difference do?
- Do sets and frozensets have the same performance?
- How do you dedupe a list but preserve order?
- What are the complexities of common set operations?
- Is set iteration/copy shallow, and how do you copy a set?
The collections Module
- What is collections.Counter and what is it good for?
- How does collections.defaultdict work, and how is it different from dict.setdefault?
- What is a collections.deque and why use it over a list?
- Is OrderedDict still useful now that regular dicts keep insertion order (3.7+)?
- What is collections.ChainMap?
- How does namedtuple fit into the collections module?
- How do you get the N most frequent items with Counter?
- How do Counters support arithmetic?
- Can a Counter hold zero or negative counts?
- What factory functions are common with defaultdict?
- What is a subtle pitfall of defaultdict?
- What does a deque's maxlen do?
- What does deque.rotate do and what are deque's complexity guarantees?
- Where do writes go in a ChainMap?
- Does OrderedDict have any methods regular dict lacks?
- When would you subclass UserDict or UserList instead of dict/list?
Python Comprehensions & Iteration
Generators & yield
- What is a generator and what does the yield keyword do?
- How does a generator save memory compared to a list?
- What is the difference between a generator expression and a list comprehension?
- What does yield from do?
- How can a generator be infinite, and why doesn't it hang?
- What does the generator `send()` method do?
- What happens when a generator uses `return`?
- What do a generator's `close()` and `throw()` methods do?
- How do you build a data-processing pipeline with generators?
- Why can you only iterate a generator once?
- How does generator laziness improve responsiveness, not just memory?
- Why write a generator instead of a class with `__iter__`/`__next__`?
- How does a generator preserve local state between `yield`s?
- How does `yield from` simplify recursive generators?
- What's a common bug when passing a generator to multiple functions?
List, Dict & Set Comprehensions
- What is a list comprehension and why use one?
- How do you filter and conditionally transform inside a comprehension?
- How do nested comprehensions work?
- What are dict and set comprehensions?
- When should you NOT use a comprehension?
- What is a generator expression and how does it differ from a list comprehension?
- Does the loop variable in a comprehension leak into the enclosing scope?
- How is the walrus operator useful inside a comprehension?
- How do you filter or transform values in a dict comprehension?
- Why is a comprehension often faster than an equivalent for-loop?
- What is the difference between `[x for row in m for x in row]` and `[[...] for ...]`?
- Can a later `for` clause depend on an earlier one in a comprehension?
- How do you avoid calling an expensive function twice in a filtered comprehension?
- What does a comprehension return when the source is empty?
- When does a comprehension become too complex and need refactoring?
Iterators & the Iterator Protocol
- What is the difference between an iterable and an iterator?
- What methods make up the iterator protocol?
- What do the built-in iter() and next() functions do?
- How do you build a custom iterator class?
- How does a for loop work under the hood?
- Why can you only iterate an iterator once?
- What does the two-argument form `iter(callable, sentinel)` do?
- How do you make a class that can be iterated multiple times?
- How do you slice an iterator without converting it to a list?
- How does `itertools.tee` let you iterate a source more than once?
- How can you peek at the next value of an iterator without consuming it?
- How do you check whether an iterator is empty?
- How does the `reversed()` built-in work and what does it require?
- Why shouldn't you let `StopIteration` leak out of a generator?
- Are `map` and `filter` iterators in Python 3?
enumerate, zip & Unpacking
- What does enumerate do and how do you set its start?
- What does zip do and how does zip_longest differ?
- How do you unzip a list of pairs with zip(*)?
- How does extended (star) unpacking work?
- How do you build a dict from zip and pass star-args in a call?
- What does `zip(..., strict=True)` do?
- Why is `enumerate` preferred over `range(len(seq))`?
- How do you combine `zip` with a comprehension for parallel processing?
- How does nested unpacking work in a for loop?
- Can you mix `*args` unpacking with regular arguments in a call?
- How do you use `*` and `**` to merge collections in literals?
- Is `zip` lazy, and what's the consequence?
- Does `enumerate` work on generators and other non-sequences?
- How does tuple unpacking enable swapping without a temp variable?
- What's a subtle bug when zipping iterables of unknown length?
Python Functions
Decorators
- What is a decorator and how does it work?
- Why should you use functools.wraps in a decorator?
- How do you write a decorator that takes arguments?
- How do you implement a decorator as a class?
- When you stack multiple decorators, in what order do they apply?
- What does the @ decorator syntax desugar to?
- What breaks if you forget functools.wraps in a decorator?
- How do you write a decorator that works with or without arguments?
- Can you decorate a class, and what does a class decorator do?
- In what order do stacked decorators apply?
- How is property a decorator?
- When does a decorator's code run?
- How do staticmethod and classmethod work as decorators?
- How can a decorator maintain state across calls?
- What is the three-level structure of a decorator with arguments?
Function Arguments
- What do *args and **kwargs do?
- What is the difference between positional and keyword arguments?
- How do default argument values work?
- What are keyword-only arguments?
- What are positional-only parameters?
- What is the correct order of parameters in a signature?
- Why is a mutable default argument dangerous?
- How do * and ** work at the call site?
- Does Python pass arguments by value or by reference?
- Does **kwargs preserve order?
- What does a bare `*` in a signature do?
- What does the `/` in a signature mean?
- What is the difference between a parameter and an argument?
- How do you forward arbitrary arguments to another function?
- When should you call with keyword arguments even if positional is allowed?
- When are default argument values evaluated?
Closures & Scope
- What is a closure and what are free variables?
- What does the nonlocal keyword do?
- Why do closures in a loop all capture the same value?
- How can you inspect a closure's captured variables?
- When should you use a closure instead of a class?
- How do you fix closures in a loop capturing the same value?
- Why prefer a closure over a global variable for shared state?
- What does "closures capture variables, not values" mean?
- How does Python implement closures under the hood?
- What is the difference between nonlocal and global?
- How do you build a simple memoizer with a closure?
- What is a function factory?
- Why does assigning to an enclosed variable without nonlocal raise UnboundLocalError?
- Do closures keep captured objects alive?
- What's the difference between capturing via closure and via default argument?
Lambdas & Higher-Order Functions
- What is a lambda and what are its limitations?
- When should you use a lambda versus a def?
- What is a higher-order function?
- How does the key argument work in sorted, max, and min?
- What does it mean that functions are first-class objects?
- Why can't a lambda contain statements?
- Can a lambda use conditionals or the walrus operator?
- Why does PEP 8 discourage assigning a lambda to a name?
- What are good uses for a lambda?
- Do lambdas capture variables the same way as nested functions?
- When should you use the operator module instead of a lambda?
- What does it mean for a higher-order function to return a function?
- Should you pair lambdas with map and filter?
- What practical patterns do first-class functions enable?
- How can an object behave like a function?
Python Object-Oriented Programming
Inheritance & the MRO
- What is the difference between single and multiple inheritance?
- What is the MRO and how is it computed?
- How does super() actually work?
- What is the diamond problem and how does Python solve it?
- What are mixins and abstract base classes?
- How should `__init__` cooperate with `super()` across a multiple-inheritance chain?
- Why prefer `isinstance` over `type(x) == SomeClass`?
- How do you override a method while still using the parent's version?
- When should you favor composition over inheritance?
- What does `__init_subclass__` let a base class do?
- How does attribute lookup use the MRO for class attributes?
- What is the difference between `super()` and `super(Class, self)`?
- Does Python support method overloading like Java?
- Can you partially implement an abstract base class in an intermediate subclass?
- How does `super()` behave inside a classmethod?
Classes, Instances & __init__
- What is the difference between a class and an instance?
- What is the difference between __init__ and __new__?
- What is `self` in Python?
- What is the difference between instance and class attributes?
- What is the difference between __repr__ and __str__?
- What happens, step by step, when you call ClassName()?
- Where does an instance store its attributes?
- What is the difference between `@classmethod` and `@staticmethod`?
- How do `getattr`, `setattr`, and `hasattr` work?
- Can `__init__` return a value?
- What happens to hashing when you define `__eq__`?
- What does a double-underscore prefix like `__name` do?
- What is a bound method versus accessing a function on the class?
- In what sense is a class itself an object?
- What does `__del__` do and why is it unreliable?
Dunder / Magic Methods
- What are dunder (magic) methods?
- How do __repr__ and __str__ control how an object prints?
- How do __eq__ and __hash__ work together?
- How do you overload operators like + and *?
- How do __len__ and __getitem__ make an object behave like a sequence?
- What does __call__ do?
- What does functools.total_ordering do?
- What is the difference between `__getattr__` and `__getattribute__`?
- How does `__setattr__` work and how do you avoid infinite recursion?
- Which dunders make an object usable in a `with` statement?
- What is the difference between `__iter__` and `__next__`?
- How do `__bool__` and `__len__` affect truthiness in `if obj:`?
- When are reflected operators like `__radd__` called?
- How does `__index__` differ from `__int__`?
- How does `__contains__` customize the `in` operator?
Methods & Properties
- What is the difference between an instance method, @classmethod, and @staticmethod?
- How do you use a classmethod as an alternative constructor?
- How does @property work with a getter and setter?
- Why do properties beat Java-style getter/setter methods?
- How do you create a computed or read-only property?
- How does `functools.cached_property` differ from `@property`?
- What does the `@x.deleter` of a property do?
- How is `@property` related to descriptors?
- Why does setting `self.x = value` in `__init__` trigger the property setter?
- Can a `@staticmethod` or `@classmethod` be called on an instance?
- What happens when you store a bound method as a callback?
- Why prefer a classmethod over a staticmethod for a factory?
- When should something be a property versus a regular method?
- How do you override a property in a subclass?
- What is the difference between `obj.method()` and `Class.method(obj)`?
Dataclasses & __slots__
- What does the @dataclass decorator generate for you?
- What does frozen=True do on a dataclass?
- Why must mutable dataclass defaults use field(default_factory=...)?
- What is __slots__ and what does it buy you?
- When would you choose a dataclass over a namedtuple or NamedTuple?
- What is __post_init__ used for?
- What can the `field()` function configure besides defaults?
- How do you convert a dataclass to a dict or tuple?
- What is the field-ordering rule when inheriting dataclasses?
- How does `kw_only=True` help with dataclass inheritance?
- What's a common pitfall combining `__slots__` with class-level defaults?
- Why might `__slots__` not save memory in a subclass?
- What does `order=True` add to a dataclass?
- How do you sort a dataclass by a computed key with `order=True`?
- How do dataclass, slotted dataclass, and NamedTuple compare on memory?
Abstract Base Classes & Protocols
- What is an abstract base class and what does @abstractmethod do?
- Why use ABCs instead of just regular classes?
- What is collections.abc and how is it useful?
- What is the difference between duck typing and ABCs?
- What is typing.Protocol and how does it relate to duck typing?
- How do you declare an abstract property or abstract classmethod?
- What does ABC `.register()` do?
- How does `__subclasshook__` enable structural isinstance checks?
- When should you choose a Protocol over an ABC?
- What is the difference between `NotImplemented` and `NotImplementedError`?
- Why does `abc.ABC` exist when there's already `ABCMeta`?
- Can an abstract method have an implementation, and why would it?
- Can a Protocol require attributes, not just methods?
- At what moment does an unimplemented abstract method raise?
- Which methods must you implement to get free mixins from `collections.abc`?
Python Errors & Exceptions
Context Managers & with
- What is a context manager and what does the with statement do?
- How do __enter__ and __exit__ work?
- How does contextlib.contextmanager simplify writing one?
- How does a context manager handle exceptions in __exit__?
- How do you use multiple context managers and what are real uses?
- How does __exit__ suppress an exception?
- What does contextlib.suppress do?
- What is contextlib.closing for?
- In a @contextmanager generator, why wrap yield in try/finally?
- What problem does contextlib.ExitStack solve?
- Can you reuse a context manager instance across multiple with blocks?
- What determines the value bound by `as` in a with statement?
- What is an async context manager?
- How do you open several context managers in one with statement?
- How do you handle an exception inside a @contextmanager generator?
try / except / else / finally
- What do the try, except, else, and finally clauses do and when does each run?
- How do you catch multiple exception types, and what does `as e` give you?
- Why is a bare `except:` considered bad practice?
- What happens when `finally` contains a `return`?
- How do you re-raise an exception and what is exception chaining?
- What is the point of the else clause on try?
- Why is the `as e` variable deleted after the except block?
- Does the order of except clauses matter?
- How do you handle several exception types the same way?
- What does `raise X from Y` do?
- Are exceptions expensive in Python?
- What happens when both try and finally return?
- How does exception propagation work through nested try blocks?
- When should you use assert instead of raising an exception?
- How do you log an exception with its traceback?
Custom Exceptions & the Hierarchy
- What is the Python exception hierarchy and why shouldn't you catch BaseException?
- How do you define a custom exception class?
- When and why should you create custom exceptions?
- How do you pass arguments and messages to an exception?
- Why does catching a base exception class also catch its subclasses?
- What are some common built-in exceptions and when are they raised?
- Why inherit from Exception and not BaseException?
- How does the args attribute and str() of an exception work?
- What are ExceptionGroup and except* (3.11+)?
- Why catch specific exceptions rather than broad ones?
- How do you re-raise an exception without losing the traceback?
- What is the EAFP pattern with exceptions?
- How do you attach structured data to a custom exception?
- How do you design an exception hierarchy for a library?
- When does finally NOT run?
- When do you use warnings instead of exceptions?
Python Functional Programming
functools
- What does functools.lru_cache do?
- What is functools.partial used for?
- Why do you use functools.wraps when writing a decorator?
- What does functools.reduce do?
- What are cached_property and singledispatch?
- What is functools.cache and how does it differ from lru_cache?
- What are the constraints on lru_cache arguments?
- What does functools.total_ordering do?
- What is functools.partialmethod?
- Why pass an initializer to functools.reduce?
- How do you register implementations with singledispatch?
- How does cached_property differ from property?
- What exactly does functools.wraps copy?
- When is functools.partial better than a lambda?
- When should you NOT use reduce?
map, filter & reduce
- What does map do and is it lazy?
- How does map work with multiple iterables?
- What does filter do?
- What is functools.reduce and why isn't it a built-in anymore?
- When should you use map/filter versus a comprehension?
- Why can a map or filter object only be consumed once?
- Is map(f, xs) the same as (f(x) for x in xs)?
- How does map with multiple iterables relate to zip?
- What does filter(None, iterable) do?
- Why do PEP 8 and idiomatic Python often prefer comprehensions?
- What is the pitfall of map/filter being lazy?
- Why did Guido move reduce out of builtins?
- Should you use map just to call a function for its side effects?
- How do you efficiently chain transformations on a large stream?
- When do you need starmap over map?
- How do you build a dict from map/zip results?
itertools
- What do count, cycle, and repeat do?
- What does itertools.chain do?
- What is islice and how is it different from regular slicing?
- What do combinations, permutations, and product produce?
- Why does itertools.groupby require sorted input?
- What does itertools.accumulate do?
- What is the main benefit of itertools being lazy?
- What is itertools.chain.from_iterable for?
- What does itertools.tee do and what's its catch?
- How does itertools.zip_longest differ from zip?
- What do takewhile and dropwhile do?
- When do you use itertools.starmap instead of map?
- What is itertools.filterfalse?
- What does itertools.pairwise do?
- How is itertools.count different from range?
- How do you correctly consume itertools.groupby output?
- Can islice do negative indices or steps?
Python Modules, Packages & Environments
The Import System
- What is the difference between a module and a package?
- What is the difference between absolute and relative imports?
- What does `if __name__ == "__main__"` do?
- How does Python find the module you import?
- What is `sys.modules` and how does it relate to circular imports?
- What does `from module import *` do and how does `__all__` control it?
- What's the practical difference between `import x` and `from x import y`?
- Why and how would you import a module lazily inside a function?
- How do you reload a module, and why is it rarely the right tool?
- What is the role of `__init__.py` in a package?
- How do you handle an optional dependency with try/except imports?
- What does `python -m package` do and why use it?
- What is a namespace package and when is it useful?
- What useful attributes does a module object have?
- What is the `__pycache__` directory and the `.pyc` files in it?
Packages & __main__
- What is the difference between a module and a package, and what does __init__.py do?
- What do `python -m` and __main__.py do?
- What does __all__ control?
- What is a namespace package?
- What is the difference between running a file and importing it?
- What's the difference between an import package and a distribution package?
- What is `pyproject.toml` and why did it replace `setup.py`?
- What does `pip install -e .` (editable install) do?
- How do you expose a command-line tool from a package?
- How do you access non-code files bundled in a package?
- When do relative imports work and when do they fail?
- How do nested subpackages and their imports work?
- What does a module-level `__getattr__` enable?
- How do you use `__init__.py` to flatten a package's public API?
- How does package structure contribute to circular imports?
Virtual Environments & pip
- What is a virtual environment and why does isolation matter?
- How do you create and activate a virtual environment?
- How do you install packages and what is requirements.txt?
- What does pip freeze do?
- What is an editable install (`pip install -e`)?
- What is pyproject.toml?
- How does activating a venv actually change your shell?
- How do `venv`, `virtualenv`, and `conda` differ?
- What do version specifiers like `==`, `>=`, `~=` mean in pip?
- When should you use `pipx` instead of `pip`?
- What does pip's dependency resolver do, and what are lock files for?
- Why should you avoid `sudo pip install`?
- How do you upgrade or remove packages with pip?
- When do you use `requirements.txt` versus declaring deps in `pyproject.toml`?
- What is the pip cache and how do you do offline installs?
Python Concurrency & Parallelism
Threading & the GIL
- What is the GIL?
- What is the difference between threading and multiprocessing?
- Why don't threads speed up CPU-bound work but help I/O-bound work?
- What is a race condition and how do locks prevent it?
- When do you use ThreadPoolExecutor vs ProcessPoolExecutor?
- Why does CPython have a GIL at all?
- When does the GIL get released?
- Is the GIL going away?
- What is the difference between Lock and RLock?
- What causes a deadlock and how do you avoid it?
- Are Python's built-in data structures thread-safe?
- What is a daemon thread?
- What does thread.join do?
- What is threading.local used for?
- Does the GIL make Python code automatically thread-safe?
Multiprocessing
- How does multiprocessing sidestep the GIL, and how is it different from threading?
- What is the difference between Process and Pool?
- How do processes communicate (Queue vs Pipe)?
- What is the pickling overhead, and what can't be pickled?
- How do you share state between processes?
- When should you use multiprocessing instead of threads or asyncio?
- Why is `if __name__ == "__main__"` required with multiprocessing?
- What are the spawn, fork, and forkserver start methods?
- What is the difference between Pool.map, imap, and apply_async?
- What does multiprocessing.shared_memory offer over Queue/Pipe?
- How does multiprocessing.Pool differ from ProcessPoolExecutor?
- What is a multiprocessing.Manager?
- How do Value and Array share state between processes?
- What happens if you don't join child processes?
- What is the overhead of multiprocessing?
- Why can Ctrl-C behave oddly with multiprocessing pools?
asyncio & async/await
- What is asyncio and the event loop?
- What do async def and await do?
- How do coroutines differ from threads?
- How do you run coroutines concurrently with asyncio.gather?
- What is the "don't block the event loop" rule?
- When does asyncio actually help?
- What is the difference between awaiting a coroutine and asyncio.create_task?
- What is the difference between asyncio.gather and asyncio.wait?
- How does gather behave when a task raises, and what does return_exceptions do?
- How do you call blocking code from async without freezing the loop?
- How do you put a timeout on an awaitable?
- How does task cancellation work in asyncio?
- What are async with and async for used for?
- How do you limit how many coroutines run at once?
- What is asyncio.Queue used for?
- Why does "asyncio.run() cannot be called from a running event loop" happen?
concurrent.futures
- What is the Executor abstraction in concurrent.futures?
- When do you use ThreadPoolExecutor vs ProcessPoolExecutor?
- What does submit() return, and what is a Future?
- How does executor.map work and how does it differ from submit?
- What does as_completed do?
- How are exceptions handled with futures?
- Why use an Executor as a context manager?
- What is the default max_workers for the executors?
- What do the timeout and chunksize arguments to map do?
- Can you cancel a submitted future?
- What does add_done_callback do?
- How does concurrent.futures relate to asyncio?
- What concurrency pitfall comes from submitting to a pool from within a pool task?
- What is the initializer argument used for?
- What does the return_when argument of concurrent.futures.wait do?
Python Memory & Internals
Garbage Collection & Reference Counting
- How does reference counting work in Python?
- Why does Python need a cyclic garbage collector?
- What does sys.getrefcount tell you and why is it always higher than expected?
- What is a weak reference and when do you use one?
- What are the pitfalls of the __del__ method?
- What is generational garbage collection?
- When might you disable the garbage collector?
- Which objects does the cyclic collector track, and which does it ignore?
- How do reference-counting bugs manifest in C extensions?
- How can you debug memory leaks with the `gc` module?
- What is `tracemalloc` used for?
- Why does a small Python object use far more memory than its raw value?
- What exactly does the `del` statement do?
- How can a weakref notify you when its referent dies?
- Why might freeing objects not return memory to the operating system?
Identity, is vs ==, & Interning
- What is the difference between is and ==?
- What does the id() function tell you?
- What is the small-int cache?
- What is string interning and sys.intern?
- Why does is sometimes "work" coincidentally?
- What is the correct use of is?
- How do identity and equality relate to hashing in dicts/sets?
- Can an object's `id()` change during its lifetime?
- Why are `None`, `True`, and `False` always safe to compare with `is`?
- Why might `a is b` be True for some tuple/string literals in the same line?
- When is `sys.intern` actually worth using?
- Why should a custom `__eq__` usually agree with identity for the same object?
- How do `copy`, slicing, and assignment differ in identity?
- What other cached singletons exist besides small ints?
- How can `id()` help diagnose an aliasing bug?
The CPython Execution Model
- How does CPython go from source to running code?
- What is CPython, and how does it differ from PyPy and Jython?
- How do you inspect bytecode with the dis module?
- What are frames and the call stack?
- Is Python compiled or interpreted?
- What role does the GIL play in CPython's execution model?
- What is a code object and how does it relate to a function?
- How does CPython decide whether to reuse a `.pyc` file?
- What compile-time optimizations does CPython apply?
- What did the 3.11+ "specializing adaptive interpreter" change?
- Why is CPython called a "stack-based" virtual machine?
- How does CPython resolve a name at the bytecode level?
- Why does Python have a recursion limit, and how do you change it?
- Does CPython optimize tail recursion?
- What constants does the compiler deduplicate within a code object?
Python Type Hints & Typing
Type Hints & Annotations
- Are type hints enforced at runtime?
- What is the difference between Optional, Union, and the `|` operator?
- What is the difference between `list` and `List`, and how do generics work?
- What is the difference between `typing.Any` and `object`?
- What does mypy do, and how is it different from Protocol-based typing?
- How do you annotate a function or callable parameter?
- How do you create a type alias?
- What's the difference between annotating with `MyClass` and `type[MyClass]`?
- What do `Literal` and `Final` express?
- What is `TypedDict` and when do you use it?
- How do you annotate a method that returns its own class?
- What are forward references and `from __future__ import annotations`?
- How do you annotate `*args` and `**kwargs`?
- How do you annotate functions that return nothing or never return?
- What is gradual typing and how do you adopt hints incrementally?
Generics & Protocols
- What are TypeVar and Generic, and how do you write a generic class?
- What is a bounded or constrained TypeVar?
- What is typing.Protocol and how does it enable structural typing?
- What does @runtime_checkable do for a Protocol?
- How do you type a function passed as an argument?
- What is the difference between covariance and invariance in generics?
- How do you use multiple type variables in one function or class?
- What is typing.Self and when is it useful?
- What does @typing.overload do?
- What problem does ParamSpec solve?
- How do you write a generic Protocol?
- Can a Protocol declare attributes, not just methods?
- How do you declare a covariant or contravariant TypeVar?
- What is the PEP 695 type-parameter syntax in Python 3.12?
- When should you use a Protocol versus an abstract base class?
Python Standard Library Essentials
Regular Expressions
- What is the difference between re.match, re.search, and re.fullmatch?
- How do capture groups and named groups work?
- What does re.compile do, and why would you use it?
- What is the difference between greedy and non-greedy matching?
- How does re.sub work, and why use raw strings for patterns?
- What is the difference between `findall` and `finditer`?
- What do the common regex flags do (IGNORECASE, MULTILINE, DOTALL, VERBOSE)?
- What do `^`, `$`, `\b`, and `\B` anchor?
- How do backreferences work in a pattern?
- How does `re.split` differ from `str.split`?
- What is catastrophic backtracking and how do you avoid it?
- What are lookahead and lookbehind assertions?
- What information does a Match object provide?
- How do you limit replacements or count them with `re.sub`?
- How do you match a literal string that may contain regex metacharacters?
Files, pathlib & os
- Why open files with the `with` statement?
- What is the difference between iterating a file and read()/readlines()?
- What is the difference between text and binary mode, and why specify encoding?
- What is pathlib.Path and how does it compare to os.path?
- How do you find files with globbing using pathlib?
- What do the file modes `r`, `w`, `a`, `x`, and `+` mean?
- What are the key parts of a `Path` (name, stem, suffix, parent)?
- How do you resolve, and work with relative vs absolute paths?
- What are `Path.read_text`, `write_text`, and their bytes variants?
- How do common `os`/`shutil` operations map to `pathlib`?
- How do you safely create temporary files and directories?
- What do `seek()` and `tell()` do on a file object?
- What's the difference between glob wildcards `*`, `**`, `?`, and `[...]`?
- Why might written data not appear in a file immediately?
- How do you handle decoding errors when reading text files?
datetime
- What is the difference between datetime, date, and time?
- What is the difference between naive and timezone-aware datetimes?
- What is the difference between strftime and strptime?
- How does timedelta arithmetic work?
- What is the pitfall with datetime.now() vs utcnow()?
- How do you parse and produce ISO 8601 datetime strings?
- How do you convert between datetimes and Unix timestamps?
- How does `zoneinfo` handle Daylight Saving Time transitions?
- What are the most common `strftime`/`strptime` format codes?
- Why are datetime objects immutable and how do you "modify" one?
- What's the modern replacement for `datetime.utcnow()`?
- How do you compare and sort datetimes?
- When do you use the `time` module instead of `datetime`?
- How do you get the weekday or work with calendar info?
- How do you parse a string into a timezone-aware datetime?
JSON, CSV & pickle
- How do json.dumps and json.loads work, and how do Python types map to JSON?
- How do you serialize an object JSON doesn't support by default?
- What is the difference between csv.reader and csv.DictReader?
- What is the difference between pickle and json, and what is the security warning?
- How do you serialize datetimes to JSON and back?
- What options control JSON output formatting?
- How does `object_hook` reconstruct custom types when loading JSON?
- How do you write CSV files correctly?
- What happens to special floats and big numbers in JSON?
- What are pickle protocols and what can't be pickled?
- What are safer alternatives to pickle for persistence?
- What happens to non-string dict keys when serializing to JSON?
- How do you handle non-comma delimiters and quoting in CSV?
- How do you handle JSON files too large to fit in memory?
- How do you serialize a dataclass to JSON and back?
Python Testing
pytest Essentials
- What is the difference between pytest and unittest?
- What are pytest fixtures, and what does scope control?
- How does @pytest.mark.parametrize work?
- How do you mock with monkeypatch versus unittest.mock?
- How do you assert that code raises an exception?
- What is conftest.py used for?
- How do you do setup and teardown in a pytest fixture?
- What are some useful built-in pytest fixtures?
- What do `skip`, `skipif`, and `xfail` markers do?
- How do you give parametrized cases readable IDs or parametrize a fixture?
- How can fixtures depend on other fixtures?
- How does pytest give detailed output from a plain `assert`?
- How do you assert floating-point equality in pytest?
- How does pytest discover which tests to run?
- What is an autouse fixture, and when should you use one?
Mocking & Patching
- What is mocking and why do you use it?
- What is the difference between Mock and MagicMock?
- How does unittest.mock.patch work, and what does "patch where it's used" mean?
- What is the difference between return_value and side_effect?
- How do you assert a mock was called correctly?
- What is autospec and why is it useful?
- When do you use `patch.object` instead of `patch`?
- How do you temporarily patch a dictionary or environment variables?
- What's the difference between `spec`, `spec_set`, and `autospec`?
- How do you mock a property or attribute (not a method)?
- How do you mock an object used as a context manager?
- What are the downsides of over-mocking?
- How does `mock_open` simplify testing file I/O?
- How do you reset a mock's recorded calls between assertions?
- How do you mock an async function or coroutine?
Python Pythonic Idioms
EAFP vs LBYL
- What do EAFP and LBYL mean?
- Why is EAFP preferred in Python?
- What race condition does LBYL invite?
- When should you use dict.get versus checking for a key?
- What are the pitfalls of EAFP, and how do you avoid them?
- When is LBYL actually the better choice?
- How does `getattr` with a default express EAFP for attributes?
- How does `contextlib.suppress` clean up EAFP code?
- How does EAFP support duck typing better than type checks?
- Is EAFP or LBYL faster?
- How does the `try/except/else` clause refine EAFP?
- When is `defaultdict` better than `dict.get` for accumulation?
- Why does EAFP depend on catching the right specific exception?
- Where should LBYL-style validation live in an application?
- How can the walrus operator support concise EAFP-style loops?
PEP 8 & Style
- What is PEP 8?
- What are PEP 8's naming conventions?
- What does PEP 8 say about imports and line length?
- What is the Zen of Python?
- What are black and ruff, and how do formatters differ from linters?
- When is it acceptable to break PEP 8?
- What are PEP 8's key whitespace rules?
- How many blank lines does PEP 8 recommend between definitions?
- What does PEP 257 say about docstrings?
- What does PEP 8 recommend for comparisons to None and booleans?
- How should you break long lines in PEP 8 style?
- What are the PEP 8 spacing rules for type annotations?
- What's the difference between `_name`, `__name`, and `__name__` conventions?
- What small formatting details does PEP 8 require at line and file level?
- Does PEP 8 mandate single or double quotes?
Common Gotchas & Anti-patterns
- Why is a mutable default argument a gotcha?
- What is the late-binding closure gotcha in loops?
- What goes wrong when you modify a list while iterating it?
- Why does `is` give surprising results on numbers and strings?
- Why is a bare except an anti-pattern?
- Why is a mutable class attribute a common bug?
- What is the problem with shadowing builtins?
- Why does `0.1 + 0.2 == 0.3` return False?
- Why does `a += b` behave differently for lists than `a = a + b`?
- What's wrong with `dict.fromkeys(keys, [])`?
- Why can `if not value:` be a subtle bug?
- Why is building a string with `+=` in a loop a performance gotcha?
- Why does copying a list with `=` not actually copy it?
- Why doesn't a default like `time.time()` update on each call?
- Why is `(1)` not a tuple?
More ways to practice
The self-quiz is live. Get notified when mock interviews and new question packs drop.
or
Join our WhatsApp Channel