What is the difference between a list and a tuple?
A list is mutable. A tuple is not. Use a list when the collection changes, and a tuple for a fixed record. A tuple can be a dict key only when every item in it is hashable. A list never can.
Interviews
A useful Python interview asks how the candidate models data, handles errors, and shares state, then watches them write a small function. The questions below are for a junior, a mid-level engineer, and a senior. Each one says what a good answer covers. After the conversation, watch the candidate code.
A junior answer names the rule and the bug it prevents.
A list is mutable. A tuple is not. Use a list when the collection changes, and a tuple for a fixed record. A tuple can be a dict key only when every item in it is hashable. A list never can.
== asks whether two values are equal, through __eq__. is asks whether two names point at the same object. Use is for None. Do not use is to compare numbers or strings, even when a small integer happens to share an object.
The default object is created once, when the function is defined, and reused on later calls. A caller that appends to it changes the default for every later caller. Use None as the default and create a new list or dict inside the function.
Catch the specific type when the function can recover or add context and raise again. Let it propagate when the caller must decide. A bare except also catches KeyboardInterrupt and SystemExit. Catch Exception, or a narrower type, on purpose.
A comprehension builds a new list. It is an expression, so it fits a filter and a transform. A loop is clearer when the body has several steps or a side effect. A comprehension that hides a network call is harder to read than the loop.
It gives one project its own interpreter and installed packages, separate from other projects on the machine. Install that project's dependencies into the environment and record them, so a later install can rebuild the same set.
A mid-level answer names the mechanism and a failure mode.
In the default CPython build, the GIL lets one thread run Python bytecode at a time. CPU-bound threads do not speed up across cores. Threads that spend their time waiting on I/O can still overlap. CPU parallelism uses processes. A good answer names the runtime, because a free-threaded build changes that limit.
Prefer not to share it. Pass work through a queue.Queue, which is safe for threads. If threads must share a structure, protect every read-modify-write with a lock, and acquire locks in one order so two threads cannot deadlock. The GIL does not make a compound update atomic.
An instance method receives the instance. A class method receives the class, which is how an alternate constructor stays overridable in a subclass. A static method receives neither. It is a function stored on the class. Use a class method when the subclass must be part of the result.
An async function runs on an event loop and yields at await. It does not add a thread. A blocking call inside it stalls every other task on that loop. Move blocking work with asyncio.to_thread, or to a process, when the wait is not an awaitable.
Mapping, from collections.abc, says the function only reads. A dict annotation rejects other mappings and promises that mutation is allowed. Return a dict when the function creates one. Annotate the parameter with the narrowest capability it uses.
It must release the resource in __exit__ whether the block returns or raises. Files, locks, and transactions are the usual cases. contextlib.contextmanager can wrap a generator that acquires, yields once, and releases in a finally. Swallowing the error inside __exit__ hides a failure the caller needed.
A senior answer names the tradeoff, the failure, and what to measure.
Keep the documented signature, return value, and exceptions stable. Add a new parameter as keyword-only, with a default that preserves the old behavior. Deprecate a behavior before removing it. Tests should pin the contract callers use, not the private helpers.
Take tracemalloc snapshots over time and compare what is still referenced. Look for a cache with no bound, a global registry, and a cycle that a __del__ method keeps alive. Growth that tracks traffic and never falls back after a quiet period is the symptom. Measure before rewriting the cache.
Use processes when the work is CPU-bound and the jobs do not need a shared mutable object. Use asyncio when the work is many waits on one thread. A service that does both can run an event loop for sockets and a process pool for the CPU jobs. Processes pay for startup and for copying data across the boundary.
A descriptor is an object on the class that implements __get__, __set__, or __delete__. A property is a descriptor. Reading the attribute on an instance calls those methods. A data descriptor on the class overrides an entry in the instance dictionary. A non-data descriptor does not.
Equality and the hash follow the fields, so every field must itself be hashable and should be immutable; frozen=True only blocks assigning to the dataclass's own fields.
The caller cannot tell a failure from a result. Log the traceback and let an unexpected error surface. Catching Exception does not catch BaseException, so it is not a reason to turn bugs into a normal return. A request handler that does this reports success for a failed write.
These questions show how a candidate talks about Python. They do not show the candidate writing the next change with no assistant. How to tell if a developer can code without AI explains the watched session.
What the candidate shows us is proctored tests, watched by a real person: a coding test with no AI allowed, a 2-hour build project with AI allowed, the Fire Drill (a live pair-programming session on a real-world problem), an English test, a thinking-skills test and a typing test. It also covers recorded reference checks. The menu is on Proctored tests. You pay for the tests you order. A real person watches.
When the answers are strong, Hire backend developers. Arca.ph is a network of remote engineers. Your own AI agent, such as Grok, Claude, or ChatGPT, searches and sorts that network. On the marketplace, the fee is a one-time 15% fee of first-year pay, only on hire, with a 3-month free replacement. Done for you is 35% of first-year pay, charged once on hire. Details are on pricing and how it works.
Values, types, and the event loop, with what a good answer covers at each level.
State, effects, and rendering, with what a good React answer covers at each level.
The event loop, APIs, and failures, with what a good Node.js answer covers at each level.
Types, concurrency, and failure, with what a good Java answer covers at each level.
Ask two or three questions from the level you are hiring, then ask what would break. A useful interview is a conversation about a real constraint. It is not a recital of every question on this page. Use the watched coding check before you decide to hire.
A junior answer names the rule and the common bug. A mid-level answer names the mechanism and one failure mode. A senior answer names a tradeoff, a failure they have seen, and what they would measure. Hire for the work the role will own, not for a perfect score on every question.
Questions do not show the candidate writing code. What the candidate shows us is proctored tests, watched by a real person: a coding test with no AI allowed, a 2-hour build project with AI allowed, the Fire Drill (a live pair-programming session on a real-world problem), an English test, a thinking-skills test and a typing test. It also covers recorded reference checks. The guide How to tell if a developer can code without AI explains the watched session.
Open the backend developer hire page linked on this page. Python is one of the stacks listed for that role. Your own AI agent searches and sorts the Arca.ph network. You choose who to test and who to interview. Profiles are free to view once you sign up and sign the Arca.ph Client Agreement.
Arca.ph is a network of remote engineers. Your own AI agent, such as Grok, Claude, or ChatGPT, searches and sorts that network. On the marketplace, the fee is a one-time 15% fee of first-year pay, only on hire, with a 3-month free replacement. Done for you is 35% of first-year pay, charged once on hire.
Profiles are free to view once you sign up and sign the Arca.ph Client Agreement.