In this article
  1. Types and equality
  2. Functions and arguments
  3. Objects and classes
  4. Iteration and memory
  5. Errors and threads
  6. Follow-up questions
  7. Sources

Types and equality

These basics sit under every round in the coding interview guide.

What is the difference between mutable and immutable types in Python?

A mutable object can change in place and an immutable one cannot. Lists, dictionaries and sets are mutable; numbers, strings and tuples are immutable. In the run, appending to a list left it the same object, while assigning to an element of a tuple raised a TypeError. Mutability matters because several names can point at one mutable object, so a change through one name shows through the others.

Why it is asked: it underlies aliasing, hashing and default-argument bugs. Read the full explanation: Python glossary, hashable.

What is the difference between a list, a tuple, a set and a dict?

A list is an ordered, changeable sequence. A tuple is an ordered sequence that cannot change. A set holds unique items with no position, and checks membership by hashing. A dict maps unique keys to values and, in the run, kept the order in which keys were inserted. Choose a tuple for a fixed record, a set for membership and deduplication, and a dict for lookup by key.

Why it is asked: it checks that you pick a structure for its access pattern. Read the full explanation: hash map versus hash set.

What is the difference between is and ==?

The == operator asks whether two objects have equal values; is asks whether they are the very same object. In the run, [1, 2] == [1, 2] was true and [1, 2] is [1, 2] stored in two names was false. Use == for values and is only for singletons such as None. Slicing a list with [:] made a new object, while b = a made a second name for the same one.

Why it is asked: confusing identity with equality causes quiet bugs. Read the full explanation: Python data model.

If the hashes of two objects are equal, are the two objects equal?

No. The data model requires only that objects which compare equal have the same hash value (Python language reference, October 2026); the reverse is not promised. In the run, two objects with a constant hash of 7 and different values collided but compared unequal, so a set kept both. Equal hashes only send both objects to the same bucket, where equality decides.

Why it is asked: it shows whether you know how hash tables resolve collisions. Read the full explanation: hash map versus hash set.

Why can a list not be a dictionary key?

A dictionary key must be hashable. An object is called hashable when its hash value never changes during its life and it can be compared with other objects (Python glossary, October 2026). A list is mutable, so its contents, and any hash built from them, could change after insertion. Python raises a TypeError for {[1]: 1}. A tuple works as a key only if its elements are hashable; a tuple holding a list fails the same way.

Why it is asked: it links mutability to how hash tables work. Read the full explanation: Python glossary, hashable.

Functions and arguments

What do *args and **kwargs do?

In a function definition, *args collects extra positional arguments into a tuple, and **kwargs collects extra keyword arguments into a dictionary; parameters after *args can only be passed by keyword (Python tutorial, October 2026). Calling f(1, 2, 3, k=4, z=5) on def f(a, *args, k=0, **kw) gave a=1, args=(2, 3), k=4 and kw={"z": 5}.1 They let a wrapper pass any arguments through unchanged.

Why it is asked: it tests flexible signatures and decorators. Read the full explanation: Python tutorial, defining functions.

Why is a mutable default argument a bug?

Python evaluates a default value once, when the function is defined, so a list default is shared by every call that omits it (Python tutorial, October 2026). Calling g(1), g(2) and g(3) on def g(x, L=[]) returned [1], [1, 2] and [1, 2, 3]. The fix is a default of None, with L = [] created inside the function when it is None.

Why it is asked: it is the best-known Python trap and shows whether you know when defaults run. Read the full explanation: Python tutorial, default argument values.

Why do lambdas created in a loop all return the same value?

A closure looks up a variable when it runs, not when it is created. Three lambdas built in for i in range(3) all returned 2, the final value of i, because they share the one i. Bind the current value with a default argument, lambda i=i: i, which returned 0, 1 and 2. The lookup order is local, enclosing, global, then built-in, often written LEGB (local, enclosing, global, built-in).

Why it is asked: it probes your model of scope and closures. Read the full explanation: JavaScript closures, the same trap.

What is a decorator?

A decorator is a function that takes a function and returns another function, applied with the @ syntax, which is shorthand for f = decorator(f) (Python glossary, October 2026). A wrapper typically accepts *args and **kwargs, calls the original and adds behaviour such as timing or logging. Add functools.wraps so the wrapped function keeps its name; in the run add.__name__ stayed "add".

Why it is asked: it combines closures, first-class functions and argument passing. Read the full explanation: Python glossary, decorator.

Knowing it is half the job. Saying it is the other half.

Interview Clozo is an AI interview copilot for real interview rounds: it hears the question and puts a strong answer on your screen, and you say it in your own words. See the features or how it works.

Start Free Trial →

Objects and classes

What is the difference between a shallow copy and a deep copy?

A shallow copy makes a new container holding references to the original's items; a deep copy recursively makes copies of the items too (Python copy module, October 2026). In the run, a shallow copy of [[1, 2], [3]] showed a later append(99) on the inner list, giving [1, 2, 99], while the deep copy stayed [1, 2]. The difference only matters for compound objects, such as containers of containers.

Why it is asked: it separates copying a name from copying data. Read the full explanation: Python copy module.

What is the difference between __str__ and __repr__?

The __repr__ method should give an unambiguous representation, ideally valid Python, for developers; __str__ gives a more convenient or concise form for readers, and need not be valid Python (Python language reference, October 2026). For a date in the run, str gave 2026-10-24 and repr gave datetime.date(2026, 10, 24). If you define only one, define __repr__.

Why it is asked: it checks debugging habits and protocol knowledge. Read the full explanation: Python data model.

What is the difference between @staticmethod and @classmethod?

A class method receives the class as its first argument, so it works with subclasses; a static method receives nothing extra and is a plain function stored in the class. In the run, make declared on C returned "C" when called on C and "D" when called on a subclass D, and the static add(1, 2) returned 3. Use a class method for alternative constructors, and a static method for a helper.

Why it is asked: it tests how methods bind to classes. Read the full explanation: Python glossary, decorator.

Iteration and memory

What is the difference between an iterable and an iterator?

An iterable can return its members one at a time and works in a for loop; an iterator is the object that does the returning, one item per next() call, raising StopIteration when finished (Python glossary, October 2026). A list is iterable and makes a fresh iterator each time. An iterator is exhausted after one pass: a second list() of the same generator returned an empty list.

Why it is asked: it explains for loops, generators and one-pass streams. Read the full explanation: Python glossary, iterator.

How do you write a generator that yields even numbers?

A generator is a function that contains yield and hands back one value at a time. For example:

def evens(limit):
    for n in range(limit + 1):
        if n % 2 == 0:
            yield n

Calling list(evens(10)) gave [0, 2, 4, 6, 8, 10]. The function does not run until iterated, and it pauses at each yield, keeping its place, so it never builds the full list.1 A shorter form is range(0, limit + 1, 2).

Why it is asked: it checks that you can write lazy code and know why. Read the full explanation: Python glossary, generator.

Why use a generator expression instead of a list comprehension?

A generator expression produces items one at a time, so its memory stays small, while a list comprehension builds every item at once. For one million squares in the run, the list object took 8,448,728 bytes and the generator object 200 bytes.1 The trade-off is that a generator can be consumed only once and has no length or indexing. Use it when you loop once or feed sum or max.

Why it is asked: it probes memory awareness. Read the full explanation: Python glossary, generator.

How does Python manage memory?

Reference counting is the scheme that CPython, the standard implementation, uses: it counts the references to each object and frees an object when its count reaches zero. The garbage collector supplements reference counting, and the documentation says you can disable it if you are sure your program creates no reference cycles (Python gc module, October 2026). In the run, two objects pointing at each other stayed alive after del and were freed by gc.collect(). The collector sorts objects into three generations.

Why it is asked: it separates users from people who know what runs underneath. Read the full explanation: Python gc module.

Errors and threads

What do else and finally do in a try statement?

The else block runs only if the try body raised no exception, and finally runs whether or not an exception occurred, as the last task before the statement completes (Python tutorial, errors, October 2026). The run printed try, else, finally with no error, and try, finally when the body returned, skipping else. Put only the risky line in try, so an error in the else code is not caught by the except clause meant for the risky line.

Why it is asked: it tests control flow on the failure path. Read the full explanation: Python tutorial, errors.

Try, except, else and finally: which block runs on which pathFlow from the try body: with no error it goes to else then finally; when an exception is raised it goes to except then finally; on a return it goes straight to finally.no errorraisedreturntry bodyruns firstelse blockif nothing raisedexcept blockif error caughtfinally blockruns lastDiagram: Interview Clozo, CC BY 4.0 ·interview.clozo.ai/blog/python-interview-questions.html
Else is the no-error path, except is the raised path, and finally runs after every path, including a return.CC BY 4.0 — source: Python interview questions on types, hashing, arguments, generators and threads
Text description of the diagram
  • When the try body raises nothing, the order printed is try, else, finally.
  • When the try body returns, the order printed is try, finally, and the else block is skipped.

What does the with statement do?

The with statement runs setup code on entry and cleanup on exit, and the cleanup runs even if the body raises an error. The Python tutorial says it lets objects like files be cleaned up promptly and correctly (Python tutorial, errors, October 2026). In the run, a custom context manager logged enter, body, exit and then the caught error, in that order. Use it for files, locks and connections.

Why it is asked: it checks resource handling beyond try and finally. Read the full explanation: Python glossary, context manager.

What is the global interpreter lock?

The global interpreter lock (GIL) is the mechanism in CPython that lets only one thread execute Python bytecode at a time. It is released during input and output, so threads still help with waiting, but they do not speed up Python code that is bound by the central processing unit (CPU). As of Python 3.13 a build option can disable it, and the documentation points to Python Enhancement Proposal (PEP) 703 (Python glossary, October 2026). Use processes for CPU-bound work.

Why it is asked: it separates concurrency from parallelism. Read the full explanation: concurrency interview questions.

What counts as false in an if statement?

None, False, zero of any numeric type and empty sequences and collections are false; any other object is true unless its class defines __bool__ returning False or __len__ returning 0 (Python documentation, Truth Value Testing, accessed 24 October 2026). In the run, 0, "", [], {} and None were false, while the string "0" and the list [0] were true; an instance of a class with __bool__ returning False and one with __len__ returning 0 were both false, and a plain object() was true. This lets you write if items: instead of if len(items) > 0:. Compare with is None when None and an empty value must be told apart.

Why it is asked: it tests an idiom that causes bugs when 0 is a valid value. Read the full explanation: Python documentation, truth value testing.

Follow-up questions

What are the basic Python skills?

Know the built-in types and when to use each, write functions with defaults and keyword arguments, read and write files with with, handle exceptions, and use comprehensions and generators. The groups above are that checklist. For counting patterns, see defaultdict.

How many Python interview questions should I prepare?

Prepare depth, not a count. Twenty questions understood well, each run and explained aloud, serve you better than a long list memorised without running it. Most rounds then move to writing code, so practise the coding interview routine and see how the round fits the interview loop.

How do I prepare for a Python coding round?

Run each snippet above, change one value, and predict the result before running it again. Then solve problems with a timer while speaking your reasoning. For the design side of the same loop, read the system design guide.

Is Python pass-by-value or pass-by-reference?

Python passes a reference to the object by value, so neither label fits well. A function receives a reference to the object, so changing a mutable argument in place shows outside, while rebinding the parameter name does not. The mutable-default entry above is the same idea.

Key takeaways
  • Mutable objects change in place; only hashable objects can be dictionary keys or set members.
  • Equal objects must have equal hashes, but equal hashes do not make objects equal.
  • A default argument is evaluated once; use None and create the object inside.
  • Generators and iterators are lazy and single-pass; lists build everything at once.
  • Reference counting frees most objects; the collector handles cycles; the lock limits CPU-bound threads.

Sources

  1. More on Defining Functions: default argument values and arbitrary argument lists (The Python Tutorial, Python 3.15 documentation) — Python Software Foundation (footer: last updated 24 October 2026), 24 Oct 2026
  2. Data model: object.__hash__, __eq__ and __str__ (The Python Language Reference, Python 3.15 documentation) — Python Software Foundation (read 2026-10-24), 24 Oct 2026
  3. copy: shallow and deep copy operations (The Python Standard Library) — Python Software Foundation (footer: last updated 24 October 2026), 24 Oct 2026
  4. Glossary (Python 3.15 documentation) — Python Software Foundation (read 2026-10-24), 24 Oct 2026
  5. gc: Garbage Collector interface (The Python Standard Library) — Python Software Foundation (footer: last updated 24 October 2026), 24 Oct 2026
  6. Errors and Exceptions (The Python Tutorial) — Python Software Foundation (footer: last updated 24 October 2026), 24 Oct 2026
  7. Truth Value Testing (The Python Standard Library: Built-in Types) — Python Software Foundation (read 2026-10-24), 24 Oct 2026