Skip to content
Interviewpedia™

Topic preparation guide

Python interview questions and answers

Practise Python through small examples you can explain and test. The set covers object identity, collections, copying, iteration and concurrency, then asks you to reason about memory and performance in a data pipeline.

What interviewers are assessing

  • Object behaviour: reason accurately about names, mutability, identity and copies.
  • Working examples: demonstrate a concept with a small input and an observable result.
  • Runtime judgement: distinguish waiting on I/O from CPU work and measure the actual constraint before optimising.

How to approach your answer

  1. State the concept in plain language and demonstrate it with a minimal example.
  2. Explain the important edge case, such as aliasing within a nested structure or shared mutable state.
  3. For a performance scenario, identify what you would measure and compare a safe alternative against the original behaviour.

Why is a mutable default argument risky?

Illustrative explanation: default argument expressions are evaluated when the function is defined, so repeated calls can share the same list. If the function appends to that list, a later call may see earlier values. I would normally use None as the default and create a list inside the function when no value was supplied. I would demonstrate two calls and test that the corrected version creates independent results. If shared state is intentional, I would make that behaviour explicit rather than hide it in a default.

Mistakes to avoid

  • Saying assignment copies an object.
  • Assuming an async function makes CPU-intensive work parallel.
  • Optimising a pipeline without checking memory, input size and where time is spent.

Questions and answer guidance

Start with the level closest to your experience. Each question links to its exact practice exercise; the answer is also available here without opening the app.

Foundations

Start with the concepts and explain them using a small example.

Technical · Fresher

1. What does it mean that names bind to objects in Python?

Read the answer guide

In Python a variable is just a name pointing at an object, so writing b = a does not copy anything; both names now refer to the same object. For immutable values like integers this is invisible, but with a list, changing it through b also changes what a sees, because there is only one list. A simple example is appending to b and then printing a. If you want an independent copy you must ask for one, for example with list(a) or a.copy(), and id() lets you confirm two names share an object.

What the interviewer is assessing

Whether you understand that assignment attaches names to objects rather than copying values into boxes.

Common mistakes

  • Says a variable is a box that stores a value, which fails to explain aliasing.
  • Believes b = a duplicates a list, then is surprised when edits show up in both.

Practise a follow-up

  • How would you demonstrate aliasing with a list?
  • How does passing a list into a function relate to name binding?
Practise this question →
Technical · Fresher

2. What is the difference between is and ==?

Read the answer guide

The operator == compares values, so it asks whether two objects are equal according to their __eq__ method. The operator is compares identity, meaning both names point at the very same object in memory. Use is for singletons, mainly None, as in if x is None, and use == for everything else such as numbers, strings and lists. Two separate lists holding the same items are equal but not identical, which a quick experiment with a and b built separately shows clearly.

What the interviewer is assessing

Whether you can separate value equality from object identity and pick the right operator each time.

Common mistakes

  • Treats is and == as interchangeable spellings of the same comparison.
  • Uses is to compare strings or numbers and relies on it working by luck of caching.

Practise a follow-up

  • Why can small integer examples mislead you?
  • Why is a custom class allowed to change what == returns?
Practise this question →
Technical · Fresher

3. When would you use a tuple rather than a list?

Read the answer guide

Choose a tuple for a small fixed record whose shape does not change, such as a coordinate pair or a row returned from a query, and a list for a collection that grows, shrinks or is reordered. Tuples signal intent to readers and can be used as dictionary keys when everything inside is hashable. Be careful: a tuple only fixes which objects it holds, so a list stored inside can still be modified. A simple rule is that position carries meaning for tuples and repetition carries meaning for lists.

What the interviewer is assessing

Whether you can pick a data structure by intent and understand what immutability does and does not guarantee.

Common mistakes

  • Says tuples are just faster lists and ignores the meaning they convey.
  • Claims everything inside a tuple is frozen, forgetting a contained list can change.

Practise a follow-up

  • Can a tuple containing a list be a dictionary key?
  • When would a named tuple or dataclass be clearer than a plain tuple?
Practise this question →
Technical · Fresher

4. What does enumerate provide that manual index tracking does not?

Read the answer guide

enumerate gives you the position and the item together in each loop pass, so you do not keep a separate counter variable that you must remember to increment. That removes a common source of off-by-one mistakes and works on any iterable, including ones you cannot index such as generators. You can also pass start=1 when humans expect numbering from one. For example, for i, name in enumerate(names, start=1) prints a tidy numbered list.

What the interviewer is assessing

Whether you write clean loops that avoid manual counters and know the simple options enumerate offers.

Common mistakes

  • Uses range(len(items)) and indexes inside, which is noisier and error-prone.
  • Keeps a manual counter and forgets to update it on some branch of the loop.

Practise a follow-up

  • When would a direct value loop be clearer?
  • How would you loop over two lists together with positions?
Practise this question →
Technical · Fresher

5. Why is a mutable default argument risky in Python?

Read the answer guide

Python evaluates default argument expressions once, when the def statement runs, not on every call. So a default like an empty list becomes one shared object, and appending to it in one call changes what the next call sees. A small example is a function that adds an item to a default list and returns it; calling it twice gives a list with both items. The usual fix is to default to None and create a fresh list inside the body when None is received. Immutable defaults such as numbers, strings and tuples are safe. Reviewers often catch this with a linter rule, and a two-call unit test shows the bug clearly.

What the interviewer is assessing

Whether you know when Python evaluates defaults and can spot shared-state bugs early.

Common mistakes

  • Thinking a new default list is created on every call, so the bug is unexpected.
  • Fixing it by copying the list after use instead of using a None sentinel.

Practise a follow-up

  • Is a default tuple or string argument safe, and why?
  • How can a mutable default ever be useful on purpose, for example for caching?
Practise this question →

Applied decisions

Show how you would apply the idea to a constraint, disagreement or failure.

Technical · Mid-level

6. What is the practical difference between a shallow and a deep copy of a nested structure?

Read the answer guide

A shallow copy builds a new outer container but the inner objects are shared, so a nested list inside is the same list in both copies. A deep copy walks the structure and duplicates inner objects too, so edits to one side never leak to the other. The price is extra time and memory, and some objects such as open connections or locks should not be cloned at all. Decide by ownership: if the copy must own its data, go deep; if nested items are read-only or intentionally shared, shallow is enough and cheaper.

What the interviewer is assessing

Whether you can reason about shared nested references and choose a copy strategy based on who owns the data.

Common mistakes

  • Calls copy.copy safe for nested data without noticing the inner lists are shared.
  • Reaches for deepcopy everywhere, ignoring cost and objects that cannot be cloned.

Practise a follow-up

  • What happens to a nested list after a shallow copy?
  • How can a class control its own deep copying behaviour?
Practise this question →
Technical · Mid-level

7. Why is membership testing often faster in a set than in a list?

Read the answer guide

A set stores elements in a hash table, so checking whether an item is present jumps almost directly to the right slot and takes average constant time. A list has no such index, so in must compare item by item and cost grows with length. The trade-off is that a set uses more memory, needs hashable elements and does not keep duplicates or order. For a handful of items a list is fine, so decide by measuring with timeit on realistic sizes rather than by habit.

What the interviewer is assessing

Whether you can connect hashing to lookup speed and weigh it against memory and constraints.

Common mistakes

  • Says sets are always faster, without mentioning hashing or the memory cost.
  • Puts unhashable items in a set and cannot explain the resulting error.

Practise a follow-up

  • What happens with an expensive or inconsistent hash method?
  • How does a dictionary lookup relate to this behaviour?
Practise this question →
Technical · Mid-level

8. What is the difference between an iterable and an iterator?

Read the answer guide

An iterable is anything you can loop over because iter() on it returns an iterator. The iterator is the object that remembers where it is and hands out values through __next__ until it raises StopIteration. A list is an iterable that can give you fresh iterators each time, while a file or generator is usually its own iterator and is used up after one pass. So looping twice over a generator gives nothing the second time, unless you recreate it or cache the items.

What the interviewer is assessing

Whether you distinguish a reusable source of values from the one-shot cursor that walks through it.

Common mistakes

  • Uses the words interchangeably and cannot say why a generator is empty on second use.
  • Believes every iterator supports indexing and len like a list.

Practise a follow-up

  • How would you safely iterate twice over a file?
  • What does a for loop do behind the scenes with an iterable?
Practise this question →
Technical · Mid-level

9. What is the difference between an instance attribute and a class attribute containing a list?

Read the answer guide

A list defined in the class body lives on the class, so every instance that does not assign its own attribute shares that single list; appending through one instance shows up everywhere. An attribute assigned inside __init__ belongs to that one object. So mutable per-object state such as lists and dictionaries should be created in __init__, or with default_factory in a dataclass. Class attributes are fine for constants and shared defaults that never change, and naming them clearly avoids confusion.

What the interviewer is assessing

Whether you can spot the shared mutable class attribute pitfall and know where per-instance state belongs.

Common mistakes

  • Puts a list in the class body and is surprised that every object sees the same items.
  • Thinks assigning to self.items always mutates the shared class list.

Practise a follow-up

  • How would you expose accidental sharing with two instances?
  • When is a class attribute the right choice?
Practise this question →
Technical · Mid-level

10. When would you choose asyncio rather than a process pool?

Read the answer guide

Choose asyncio when the work is mostly waiting, such as many network calls or sockets, because one thread can interleave thousands of waiting tasks cheaply as long as the libraries are awaitable. Choose a process pool when the work is CPU-bound Python code, since separate processes avoid the interpreter lock and use several cores. A blocking call inside an async function freezes the whole loop, which is a common pitfall. Decide by profiling a realistic workload rather than by habit, and mix them by running CPU work in an executor if needed.

What the interviewer is assessing

Ability to match a concurrency model to an I/O-bound or CPU-bound workload and to weigh its overheads.

Common mistakes

  • Using asyncio for CPU-heavy loops and expecting a speed-up on multiple cores.
  • Calling blocking libraries such as requests directly inside async functions.

Practise a follow-up

  • How would you run a blocking library call from inside an asyncio program?
  • What does pickling have to do with the cost of a process pool?
Practise this question →

Senior judgement

Explain trade-offs, wider consequences and the evidence behind your decision.

Technical · Senior

11. When can a generator still cause large memory use despite lazy evaluation?

Read the answer guide

Laziness only helps if nothing keeps the produced items alive. A generator can still hold big objects in its own frame, a consumer may append every item into a list, a sorted or grouped step may buffer the whole stream, or each yielded item may itself be large. Memory then grows despite the generator. I would trace the full pipeline, find the stage that accumulates, and redesign it to work in chunks or with bounded windows, accepting the extra complexity only where data size demands it.

What the interviewer is assessing

Whether you can look past the word lazy and find where a streaming pipeline really accumulates data.

Common mistakes

  • Assumes using a generator automatically guarantees constant memory.
  • Blames Python garbage collection without checking what still references the data.

Practise a follow-up

  • How would you test memory growth over a million records?
  • Which common stages in a pipeline force buffering of everything?
Practise this question →
Technical · Senior

12. A Python data pipeline slows and memory grows when reading a large file. What would you change first?

Read the answer guide

Begin by measuring rather than guessing. Profile where the time goes and what is held in memory, since a file reader that loads everything into a list will grow with input size. Change the design to stream: read in chunks or line by line, process each record, write results out and drop references, so memory stays roughly constant. Only after that, consider parallelism, because it multiplies memory use and may not help an I/O-bound job. Confirm the gain by running a representative large file and comparing peak memory and run time before and after.

What the interviewer is assessing

Whether you profile first and fix memory growth by streaming before reaching for parallelism.

Common mistakes

  • They add multiprocessing or a bigger machine before finding out what is consuming the memory.
  • They read the whole file with readlines or a full DataFrame load because it is simpler to write.

Practise a follow-up

  • When could generators still retain large state?
  • How would you handle a file too large for one pass, such as a sort?
Practise this question →

A 30-minute practice plan

  1. 10 minutes: Run small identity, copying and mutable-default examples locally.
  2. 10 minutes: Explain an iterator and a generator, including where memory can still accumulate.
  3. 10 minutes: Compare an I/O-bound task with a CPU-bound task and justify an execution model.

Answer before reading the guide. Use feedback to improve the substance, then rehearse a follow-up without memorising the wording.

Further reading

Use these primary references to check concepts and current platform behaviour alongside the practice bank.

Make it your language

Language settings are saved on this device only.

Core interface translations are available. Some extended guidance and legal text remain in English.

Public guides remain in English where a translation is unavailable.

Voice availability depends on your browser and device. You can always type instead.

Open Library in your language