Python Interview Questions

Python interview questions: data types, list vs tuple, GIL, decorators, generators and PEP 8.

30 questions

1 What is the difference between a list and a tuple? EASY
  • list - mutable, ordered, created with [] ; you can add, remove or change items.
  • tuple - immutable, ordered, created with () ; used for fixed collections that should not change, and it can be used as a dict key.

Tuples are slightly more memory efficient and signal intent that the data is constant.

2 What is the GIL and how does it affect multithreading? MEDIUM

The GIL (Global Interpreter Lock) allows only one thread to execute Python bytecode at a time, protecting CPython internal state. This means CPU-bound Python code does not speed up with threads.

For CPU-bound work use multiple processes (multiprocessing, each gets its own GIL) or C-based libraries (numpy). For I/O-bound work threads or asyncio work well because the GIL is released during blocking I/O.

3 What are decorators and how do you write one? MEDIUM

A decorator is a function that takes a function and returns a new one, adding behaviour without changing the original source. The @name syntax applies it:

def timer(fn):
    def wrapper(*args, **kwargs):
        import time
        t0 = time.perf_counter()
        r = fn(*args, **kwargs)
        print(fn.__name__, time.perf_counter() - t0)
        return r
    return wrapper

@timer
def work():
    ...

Decorators are used for logging, caching, authentication and input validation.

4 What are generators and what is the yield keyword? MEDIUM

A generator is a function that uses yield instead of return, producing values lazily one at a time while preserving its state between calls. It does not build the whole sequence in memory.

def evens(limit):
    n = 0
    while n < limit:
        yield n
        n += 2

Great for large or infinite streams: read a huge file line by line without loading it all.

5 Explain the with statement and context managers. EASY

with open("file.txt") as f: guarantees the file is closed even if an exception occurs. The with protocol calls __enter__ on entry and __exit__ on exit (also on errors).

Locks, database connections and files should all be used as context managers to release resources reliably - no manual close/finally needed.

6 What does PEP 8 recommend and is it mandatory? EASY

PEP 8 is the official style guide: 4-space indentation, snake_case for variables/functions, CamelCase for classes, blank lines around top-level definitions, 79-column line limit and imports at the top. It is not enforced by the compiler but is expected in shared code, and tools like flake8/black help follow it.

7 What is the difference between a list, tuple and dictionary? EASY

List - ordered, mutable, indexed, duplicates allowed: [1, 2, 3]. Tuple - ordered, immutable, often used as a fixed record or dict key: (1, 2). Dictionary - unordered key-value mappings with fast lookups: {"a": 1}. Also: set - unordered unique elements for fast membership tests.

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

A shallow copy (list.copy(), copy.copy()) duplicates the outer container but shares nested objects; mutating a nested list affects the original. A deep copy (copy.deepcopy()) recursively duplicates everything, so the two structures share nothing. For JSON-like data you can also emulate a deep copy with json.loads(json.dumps(x)).

9 What is the Global Interpreter Lock (GIL) and how does it affect threading? MEDIUM

The GIL allows only one Python thread to execute bytecode at a time, even on multi-core machines. Pure-CPU work in threads does not speed up - use multiprocessing (separate processes, each with its own interpreter) for CPU-bound tasks. I/O-bound tasks still benefit from threads because the GIL is released while waiting on I/O.

10 What is the difference between a function and a generator? MEDIUM

A normal function computes and returns a result immediately. A generator (contains yield) returns an iterator that produces values lazily, one by one, pausing between yields - so it can process streams without holding everything in memory:

def squares(n):
    for i in range(n):
        yield i * i
11 What is the difference between yield and return in a generator? MEDIUM

return ends the function and hands back a value, terminating the generator (a return value in a generator marks it done). yield produces the next value of the sequence and pauses execution, resuming on the next next(); the generator state is preserved between yields. A generator can have both: yield values along the way and return to stop.

12 What is the difference between a decorator and a context manager? MEDIUM

A decorator is a function that takes a function/class and returns a wrapped version - used with the @ syntax to add cross-cutting behavior (logging, timing, auth). A context manager defines __enter__/__exit__ and is used with with to manage resources (open files, DB connections, locks) with guaranteed cleanup:

with open("f.txt") as f: data = f.read()
13 What is the difference between == and is in Python? EASY

== compares values (calls __eq__), while is compares object identity (same memory address). Small integers and short strings are cached, so 5 is 5 may be True, but large objects rarely are. Use is only for singletons: None, True, False.

14 Explain MRO (Method Resolution Order) and multiple inheritance? HARD

Python supports multiple inheritance and resolves methods by the C3 linearization, computed into __mro__. It orders ancestors so each class appears before its bases and the order is consistent (no inconsistency throws). super() follows the MRO chain, letting each class cooperate:

class A: 
class B(A): 
class C(A): 
class D(B, C):  # MRO: D, B, C, A
15 What is the difference between __str__ and __repr__? EASY

__repr__ returns an unambiguous, developer-oriented string - ideally code that recreates the object; shown in the REPL and in containers. __str__ returns a readable, user-oriented string; used by print() and str(). If only __repr__ is defined, it serves both. Example: repr of datetime is datetime(2026,1,1,...), str is "2026-01-01".

16 What is the difference between type() and isinstance()? EASY

type(x) returns the exact type of x; it does not consider inheritance, so type(child) == Parent is False. isinstance(x, cls) returns True when x is an instance of cls or of any subclass - it respects inheritance and accepts tuples of classes. Prefer isinstance() for flexible, polymorphic checks.

17 What are the common ways to iterate over a dictionary? EASY

Use for k in d for keys, for v in d.values() for values, for k, v in d.items() for both. To remove while iterating, iterate over a copy (for k in list(d)) or collect keys first. For ordered access, dicts preserve insertion order (Python 3.7+).

18 What is PEP 8 and which rules matter most? EASY

PEP 8 is Python's style guide. Key rules: 4 spaces per indentation level, lines up to 79 characters, snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants, blank lines around functions/classes, and meaningful names. Tools like black, flake8 and pylint automate compliance.

19 What is the difference between *args and **kwargs? EASY

*args collects extra positional arguments into a tuple; **kwargs collects extra keyword arguments into a dict. They also unpack when calling: f(*lst) and f(**d). Use them for flexible APIs, wrappers/decorators and forwarding arguments to base functions.

20 What is the difference between mutable and immutable types? Give examples. EASY

Immutable types cannot be changed after creation: int, float, str, tuple, bytes, frozenset. Any "change" creates a new object. Mutable types can change in place: list, dict, set, bytearray, and custom objects. This matters for defaults (never use a mutable default argument), hashing (only immutable types are generally hashable) and function argument side effects.

21 What is the difference between classmethod, staticmethod and instance method? MEDIUM

An instance method receives self and can access instance state. A classmethod (@classmethod) receives cls, can access class state and is often a factory: cls.from_string(s). A staticmethod (@staticmethod) receives neither - it is just a function grouped in the class, used for utilities that do not need the class.

22 What is the difference between __init__ and __new__? HARD

__new__ is a classmethod that creates and returns the instance; it runs first and rarely needs overriding (singletons, immutable subclasses). __init__ then initializes the already-created instance. In practice you override __init__; __new__ is needed when the object is created by machinery rather than your constructor logic.

23 What is the difference between a local variable and a global variable? MEDIUM

A global is declared at module level and visible everywhere; reading is fine inside functions, but assigning creates a local unless you declare global x. A local exists only inside its function/scope. Prefer local variables and passing arguments - global mutation is a common source of bugs. nonlocal allows rebinding in an enclosing (non-global) scope, as in closures.

24 What is the difference between iterating with a for loop and a while loop? EASY

for iterates over an iterable (list, dict, range, file lines) - clearer and safer because it manages the iterator for you. while repeats while a condition stays True - use it when the number of iterations is unknown (menu loops, waiting for a condition). Both support break/continue/else.

25 What is the benefit of f-strings over older formatting? EASY

f-strings (f"...") inline expressions directly: f"User {name}, score {score:.2f}" - readable, fast and support format specs. They replaced %-formatting ("%s" % name), .format() ("{}".format(x)) and concatenation. Python 3.8+ also added f"{expr=}" for debugging output. Keep f-strings free of complex embedded expressions for readability.

26 What is the difference between a module, a package and a library? EASY

A module is a single Python file with code. A package is a directory of modules with an __init__.py (namespace packages may omit it). A library is a broader collection - usually one or more packages distributed together (Pillow, requests). Import paths use dots: from package.module import name.

27 How do you handle exceptions and what is try/except/else/finally? EASY

try contains the risky code; except SomeError as e (or multiple excepts, tuple of errors, and bare except for anything) handles it; else runs when no exception occurred; finally always runs for cleanup. Avoid bare except, catch specific exceptions, and re-raise with raise when you only log. Modern style uses raise ... from e to preserve context.

28 What is the difference between exception, error and warning in Python? MEDIUM

Exceptions are the mechanism for handling errors - Python raises them and they can be caught. Errors (in Python) are a subclass of Exception (SyntaxError, TypeError) - the term is used loosely; many "errors" are just exception classes. Warnings are issued by the warnings module for non-fatal issues (deprecations) and do not interrupt execution - shown as "UserWarning" unless turned into errors.

29 What is the difference between requests, urllib and the http.client modules? EASY

requests is the third-party de-facto HTTP library - clean API, sessions, JSON helpers (requests.get(url).json()). urllib is stdlib (urllib.request etc.) - decent but more verbose and lower level. http.client is the lowest-level stdlib HTTP. For real projects use requests (or httpx); stdlib options exist when you cannot add dependencies.

30 What is the difference between _, __var and __var__ in naming? MEDIUM

A single _ is a throwaway variable (ignored loop value) or a weak "internal use" marker. __name (double leading underscore) triggers name mangling to _Class__name inside classes - used to avoid subclasses clobbering attributes. __name__ (dunder, leading and trailing) is reserved for Python-defined special methods (__init__, __len__) and should rarely be invented.