πŸ“š Learning Hub
Β· 4 min read
Last updated on

15 Python Interview Questions That Go Beyond the Basics


Some links in this article are affiliate links. We earn a commission at no extra cost to you when you purchase through them. Full disclosure.

Python interviews at the senior level don’t ask β€œwhat’s a list comprehension.” They test whether you understand how Python actually works under the hood. These 15 questions are the ones that matter. (Not sure Python is the right focus? See which programming language to learn for guidance.)

1. What’s the difference between a list and a generator?

A list stores all values in memory. A generator produces values one at a time, on demand.

# List β€” all 1M items in memory
squares = [x**2 for x in range(1_000_000)]

# Generator β€” one item at a time
squares = (x**2 for x in range(1_000_000))

When to use generators: When processing large datasets, reading files line by line, or when you don’t need all values at once.

2. Explain decorators

A decorator is a function that wraps another function to extend its behavior:

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.time() - start:.2f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)

Follow-up: β€œWrite a decorator that retries a function 3 times on failure.” This tests whether you can write one, not just explain one.

3. What’s the GIL and why does it matter?

The Global Interpreter Lock (GIL) allows only one thread to execute Python bytecode at a time. This means CPU-bound multithreaded Python code doesn’t run in parallel.

Workarounds:

  • multiprocessing β€” separate processes, each with its own GIL
  • asyncio β€” for I/O-bound concurrency (network, file I/O)
  • C extensions (NumPy) β€” release the GIL during computation

4. What’s the difference between is and ==?

== checks value equality. is checks identity (same object in memory).

a = [1, 2, 3]
b = [1, 2, 3]
a == b  # True β€” same values
a is b  # False β€” different objects

c = a
a is c  # True β€” same object

Gotcha: Small integers (-5 to 256) and short strings are cached, so is sometimes works by accident.

5. How does Python manage memory?

  • Reference counting β€” each object tracks how many references point to it. When count hits 0, memory is freed.
  • Garbage collector β€” handles circular references that reference counting can’t detect.
  • Memory pools β€” Python pre-allocates blocks for small objects to avoid frequent system calls.

6. What are *args and **kwargs?

*args collects positional arguments into a tuple. **kwargs collects keyword arguments into a dict.

def flexible(*args, **kwargs):
    print(args)    # (1, 2, 3)
    print(kwargs)  # {'name': 'Alice'}

flexible(1, 2, 3, name='Alice')

7. Explain Python’s MRO (Method Resolution Order)

When a class inherits from multiple parents, Python uses C3 linearization to determine which method to call:

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

D.__mro__  # (D, B, C, A, object)

super() follows the MRO, not just the direct parent.

8. What’s the difference between @staticmethod and @classmethod?

  • @staticmethod β€” no access to class or instance. Just a function namespaced to the class.
  • @classmethod β€” receives the class as first argument (cls). Can create instances, access class variables.
class User:
    @classmethod
    def from_dict(cls, data):
        return cls(data['name'], data['email'])
    
    @staticmethod
    def validate_email(email):
        return '@' in email

9. How does async/await work in Python?

async def creates a coroutine. await pauses execution until the awaited coroutine completes. The event loop manages switching between coroutines.

async def fetch_data():
    async with aiohttp.ClientSession() as session:
        resp = await session.get('https://api.example.com')
        return await resp.json()

Key insight: async is for I/O-bound concurrency, not CPU-bound parallelism. For CPU work, use multiprocessing. If you’re building web APIs, see our Django vs FastAPI comparison for how async fits into framework choice.

10. What are context managers?

Context managers handle setup/teardown with with statements:

# Built-in
with open('file.txt') as f:
    data = f.read()
# File automatically closed

# Custom
class Timer:
    def __enter__(self):
        self.start = time.time()
        return self
    def __exit__(self, *args):
        print(f"Elapsed: {time.time() - self.start:.2f}s")

11-15: Quick-fire round

11. Mutable default arguments:

# ❌ Bug β€” list is shared across calls
def add(item, lst=[]):
    lst.append(item)
    return lst

# βœ… Use None
def add(item, lst=None):
    if lst is None: lst = []
    lst.append(item)
    return lst

12. __slots__: Restricts instance attributes to a fixed set, reducing memory usage by ~40% for classes with many instances.

13. __init__ vs __new__: __new__ creates the instance, __init__ initializes it. You rarely override __new__ unless implementing singletons or immutable types.

14. Walrus operator (:=): Assigns and returns a value in one expression: if (n := len(data)) > 10: print(n)

15. dataclasses: Auto-generate __init__, __repr__, __eq__ for data-holding classes. Use them instead of writing boilerplate. If you’re preparing for your first developer job, knowing dataclasses shows you write modern Python.


Related: Python Cheat Sheet Β· Python Complete Guide

Level up your Python: Pluralsight has Python learning paths from fundamentals to advanced topics like async, decorators, and data engineering. Start a free 10-day trial.

πŸ“˜