Interview Q&A / Python
Python interview questions
Lists, dictionaries, generators, decorators and the Python questions asked in service-company and data roles.
Prefer rapid revision? Practise Python short interview answers →
- What are *args and **kwargs in Python?
In a function definition, *args collects any extra positional arguments into a tuple, and **kwargs collects any extra keyword arguments into a dict. They let a function accept a variable number of inputs. The same * and ** symbols also unpack a list or dict when calling a function.
BeginnerIn-depth3 min read - What are mutable and immutable objects in Python, and why is a mutable default argument a bug?
Mutable objects such as lists, dicts and sets can change in place; immutable ones such as int, str and tuple cannot. Default arguments are evaluated once, when the function is defined, so a list used as a default is shared across every call. Use None as the default and create the list inside the function.
BeginnerIn-depth3 min read - What is the difference between a list and a tuple in Python?
A list is mutable, so you can add, remove or change items after creating it. A tuple is immutable, so its contents are fixed once created. Tuples are slightly lighter and can be used as dictionary keys if all their items are hashable; lists cannot.
BeginnerIn-depth3 min read - What is the difference between a shallow copy and a deep copy in Python?
A shallow copy creates a new outer container but keeps references to the same inner objects, so changing a nested list affects both. A deep copy recursively copies everything inside, so the two are fully independent. Use copy.copy() for shallow and copy.deepcopy() for deep.
BeginnerIn-depth3 min read - How does a dictionary work internally in Python, and why must keys be hashable?
A dict is a hash table. Python calls hash() on the key to pick a slot, then uses == to confirm the match, which makes lookups O(1) on average. Keys must be hashable, meaning their hash never changes, otherwise the dict would look in the wrong slot and lose them. That is why lists cannot be keys but tuples of immutable values can.
IntermediateIn-depth4 min read - What is a decorator in Python and how do you write one?
A decorator is a function that takes another function, wraps it with extra behaviour, and returns the wrapped version. Writing @my_decorator above a function is shorthand for func = my_decorator(func). They are used for logging, timing, caching and access checks without changing the original function's code.
IntermediateIn-depth3 min read - What is a generator in Python, and how is yield different from return?
A generator is a function that uses yield to produce values one at a time, pausing after each one and resuming where it left off on the next request. return ends the function and gives back one result, while yield hands out a value and keeps the function's state. Generators save memory because they never build the full list.
IntermediateIn-depth3 min read - What is the GIL in Python, and when should you use threads versus multiprocessing?
The Global Interpreter Lock in CPython lets only one thread run Python bytecode at a time, so threads do not speed up CPU-heavy pure Python code. Threads still work well for I/O-bound work, because the lock is released while waiting. For CPU-bound work, use multiprocessing. Python 3.13 added an optional, experimental free-threaded build without the GIL.
AdvancedIn-depth5 min read