Python · Interview preparation
Python interview questions: short answers
The short answer from every lesson in the track — the lesson’s own text, minus the “Short answer:” label — and the questions from its “Next they ask” section. The answers to those questions, the mechanism and the measurements behind it all are in the linked lesson.
01
Classes and OOP
A class holds the attributes and methods shared by its instances, an instance of an ordinary class holds its own data in its own dictionary. A method is a function in the class,
selfis its first argument:a.m()is equivalent toA.m(a). Reading an ordinary attribute looks in the instance, then in the class; assignment through an instance writes to the instance.@classmethodreceives the class,@staticmethodreceives nothing.Next they ask
02
Built-in collections
A list is an ordered mutable collection with repeats, a tuple is immutable, a dictionary maps key → value with unique keys, a set holds unique elements without order. Membership checks and lookups by value are done on a set or a dictionary: there it is a hash lookup — O(1) on average and O(n) in the worst case, when hashes coincide — in a list it is a scan. Only a hashable object can be a set element or a dictionary key; dictionary values can be anything. A dictionary keeps insertion order, a set does not.
Next they ask
03
Modules and imports
importfinds a module and binds a name. The module body runs on the first successful load; a repeatedimportunder the same full name in the same interpreter takes the module from thesys.modulesdictionary.from m import xcopies a reference to the value at the moment of import — a new assignment tom.xdoes not change it.if __name__ == "__main__"separates launch code from code that will run on import.Next they ask
04
Complexity of operations
O-notation describes how the work grows with the input; strictly it is an upper bound.
x in list,insert(0, x),removeare O(n);x in set,d[key]are O(1) on average and O(n) in the worst case, when hashes coincide;appendis amortized O(1);bisectis O(log n);sorted()is O(n log n) in the average and worst case. The complexity of code is the number of iterations times the cost of the operation inside.Next they ask
05
Strings and formatting
A string is immutable — methods and
+=return a result, and the original string does not change. Slicess[i:j:k]do not include the right bound, negative indices count from the end, slice bounds are clipped to the string's length — so a slice entirely beyond it is empty. Format with f-strings with a specification after the colon. A string is built from many pieces with"".join(...): the documentation calls repeated concatenation quadratic, and CPython's fast path is a conditional optimization.stris Unicode code points,bytesis bytes, between them —encodeanddecode.Next they ask
06
Testing
A test calls code and checks the result; in
unittestFAIL is a check that fired (AssertionError), ERROR is any other exception. External dependencies are replaced withMockviapatch— in the module where the name is used. The main claim of a test is about the result of the code; checking the mock's call is an additional one. Mocks are built from the real object:Mock(spec=…)rejects non-existent names, while a wrong call is caught only bycreate_autospecorautospec=True. Tests are independent: they do not rely on the order in which they run, state is prepared insetUpor a fixture.Next they ask
07
Threads and processes
Threads share the memory of a process, processes are isolated. In regular CPython — the build with the GIL — threads run Python code in turn, so for waiting — network, disk — you take threads or asyncio, and for computation in Python — processes; C extensions can release the GIL themselves. Tasks are passed to processes via pickle, starting processes is more expensive, and a process pool is created in
main()underif __name__ == "__main__":. The GIL does not prevent races: shared state is protected with aLock.Next they ask
08
Environments & dependencies
A virtual environment is a folder with its own interpreter and its own
site-packages; it is created withpython -m venv. The environment's interpreter finds it by itself frompyvenv.cfg, andactivateis for the shell — throughPATHthepythoncommand finds the environment's interpreter. Packages are installed withpython -m pipinside the environment, the installed versions are recorded withpip freezeinrequirements.txt— a snapshot of what is installed, not a lock file. Packages are not installed into the system Python: an environment isolates the versions of projects.Next they ask
09
Decorators
@dabovedef fisf = d(f), run once, at the moment the interpreter reachesdef. With several decorators the expressions after@are evaluated top-down and applied bottom-up.functools.wrapsmakes the wrapper look like the target rather than behave like it:inspectreports the target's signature only because it walks__wrapped__, while the wrapper itself still accepts*args, **kwargs.Next they ask
10
Descriptors
A descriptor is an object that lives on the class and intervenes in attribute access on an instance; the single criterion is that its type has
__get__,__set__or__delete__. All the behaviour follows from one line of precedence: a data descriptor (one with__set__or__delete__) outranks the instance dictionary, a non-data descriptor (only__get__) is outranked by it.property, an ordinary method,staticmethod,classmethod, a slot andcached_propertyalready are descriptors.Next they ask
11
Iterators and generators
An iterable can hand you an iterator (
__iter__); an iterator can hand you the next item (__next__) and must hand back itself from__iter__. One method of difference, and one difference in behaviour: a list can be walked twice, an iterator cannot. A generator is an iterator written as a function, and calling a generator function does not run its body — it builds an object and returns.Next they ask
12
Context managers
A
withis a guarantee that leaving the block will be handled, however the block ends. The protocol is two methods on the type:__enter__is called on the way in,__exit__on the way out, andasbinds what__enter__returned rather than the object itself.Next they ask
13
Exceptions and finally
tryis the attempt,excepthandles the error,elseis the "no error happened" branch,finallyis the exit taken either way. And the key point aboutfinally: if it transfers control outwards itself —return,break,continue— the exception in flight disappears. The reference puts it in one sentence: "the saved exception is discarded".Next they ask
14
lambda
A
lambdais the same function written as an expression. The object it builds is of the same type as adef's, with the same bytecode for the body; you write one where the function is needed right at the call site and a separate name would hurt readability.Next they ask
15
async/await
Calling a coroutine function (
async defwithoutyield) does not run its body — it only creates acoroutineobject. The body is run by whatever drives that object:awaitin the current task,asyncio.run, or a task fromcreate_task, and a task may start working before anyone writesawait task.awaityields control to other tasks only if what it awaits is not ready yet: awaiting a finished Future hands over no turn. Hence the forgottenawait:if is_allowed(user)tests the coroutine object for truth instead of the result of the check, and so passes for any data.Next they ask
16
*args and **kwargs
A star in a declaration collects, a star in a call spreads. One star collects the surplus positional arguments into the tuple
args, two collect the surplus keyword arguments into the dictkwargs; in a call, one spreads a sequence into positional arguments and two spread a dict into keyword arguments. Both objects are built even when there is nothing to pass: you get()and{}, notNone.Next they ask
17
List vs tuple
A list is a mutable sequence and a tuple an immutable one, and that — not bytes — is what you choose between. A tuple can be a dictionary key whenever every element of it can, and it tells the reader "this is one record of a fixed shape"; a list says "this is any number of uniform things". There is a difference in memory, but it is not what you would change the type for.
Next they ask
18
Comprehensions
A comprehension is a loop written as a single expression, but it runs in a scope of its own, and the boundary of that scope is inside the square brackets rather than around them. Everything except the iterable expression in the leftmost
forruns in a separate, implicitly nested scope — which is why the comprehension's variable does not leak out, and why the comprehension does not always see the same names as the code around it.Next they ask
19
Closures
A closure is a function that kept access to the variables of the place it was created in, and goes on using them after that place has finished running. What it kept is access to the variable, not a copy of its value: the value is read at call time. That is why a change made to the variable after the function was created reaches it.
Next they ask
20
MRO
The MRO is the order in which Python looks an attribute up across the classes of a hierarchy; it lives in
Class.__mro__and is built by the C3 algorithm. C3 puts a class before its ancestors and keeps the order of the bases, so in the diamondD(Left, Right)the common ancestor goes to the tail:D, Left, Right, Base, object. Andsuper()is a proxy: lookup through it goes along the instance's MRO, starting after the class where the method is written, and that is not necessarily the parent.Next they ask
21
Copying
Assignment copies nothing — it is a second name for the same object;
copy.copybuilds a new top-level object and leaves the nested ones shared;copy.deepcopyreaches the nested ones too. The difference shows only when you change something nested: after a shallow copy the change is visible from both sides, after a deep one it is not.Next they ask
22
is versus ==
isasks whether this is the same object; it cannot be overridden, and its cost does not depend on the object.==calls__eq__, an ordinary method that may return anything.isbelongs where the API contract is identity itself: with any singleton object and any sentinel created for such a comparison —None,NotImplemented,Ellipsis,Enummembers, your ownobject().Next they ask
23
Garbage collection
In CPython memory is freed first of all by reference counting: an object dies as soon as its last reference disappears, at once.
deldeletes a name, not an object. The garbage collector supplements the count and is needed for cycles: objects that refer to each other would never be freed by the count, andgcfinds such groups with no outside references.Next they ask
24
Metaclasses
A metaclass is the type of a class. A class is an instance of its metaclass exactly as an object is an instance of its class, and a metaclass governs how classes are created in much the same way a class governs how instances are created. Hence
Class(...)calling the metaclass's__call__: the class is its instance.Next they ask
25
Default arguments
The expression after
=is evaluated once, when thedefexecutes, and the resulting object is handed to every call in which that argument is not passed. That is why a mutable default accumulates changes between calls. The fix is aNonecheck; a sentinel of your own is needed only whereNoneis a legitimate argument value.Next they ask