Home
Series About Subscribe
Python Interview Questions for Experienced Developers (Senior)

Python Interview Questions for Experienced Developers (Senior)

I've put together a series of posts with my personal database of Python interview questions. It's not perfect, it's not complete, and no, there aren't any answers included. Some of the questions might even feel a little odd or out there. But in my experience, they're great at helping you figure out who's really ready for the job.

The series is split into three parts based on experience level:

Got a question you think should be here? Or something you always ask in interviews? Let me know β€” I'd love to hear your thoughts!


We all know that a Senior developer is not only a technical role with years of experience and knowledge about their tools, they also have mentoring skills, some management skills, and they tend to have some architectural skills, etc. My questions here are only about the technical side of Senior Python developers.

What sets a senior apart isn't the volume of what they know, it's what they know not to do. Junior knows the syntax, middle knows what breaks in production, senior knows what not to build. That's why a lot of what follows is some version of "when would you not do this"β€”there's no memorized answer to those.

Some questions have a note under them about what I'm listening for.

Questions

1. Discussion Questions

Q: Python is often called an easy language. Do you agree with this statement? Why or why not?

Q: What are some pitfalls and limitations of Python as a language?

Q: How does a framework differ from a library? Can you provide examples?

Q: How do you ensure the maintainability of a large codebase? Discuss tools, static analysis, and coding practices you rely on.

Q: What is monkey patching? How to use it in Python? Example? Is it ever a good idea?

2. Python Internals

Q: How are dict and set implemented internally? What is the complexity of retrieving an item? How much memory do these structures consume?

Q: Does Python support multiple inheritance? How does it solve the diamond problem?

Q: What is MRO (Method Resolution Order) in Python? How does it work?

Q: Does Python have an assignment operator? How is assignment in Python different from C or C++?

Q: What are descriptors? How do they differ from decorators?

Q: How are function arguments passed in Python β€” by value or by reference? Explain with examples.

Q: What are .pth files in Python?

Q: Python 3.12 made some objects immortal (PEP 683) so their reference counts are never updated. Which objects, and why was that worth doing?

Anyone who has opened the PEP can recite it. The follow-up is the more interesting half: someone who has actually dug around in reference counts has a habit that 3.12 broke. Immortal objects now carry a very large refcount that doesn't reflect the real number of references, so sys.getrefcount() can't be trusted for anything except telling 0 from 1. The question is whether they know that. Someone who only read about refcounts won't notice any difference and will say nothing changed.

  • Follow-up: What does that change about how you reason about sys.getrefcount()?

3. Typing

Q: Python 3.12 introduced new syntax for generics and a type statement (PEP 695). What problem does it solve that TypeVar didn't?

  • Follow-up: When would you reach for a Protocol instead of an abstract base class?
  • Follow-up: Type hints are not enforced at runtime. So what are they actually buying you?

Q: You've inherited a large untyped codebase and you're asked to add type checking. How would you sequence that work, and how would you keep it from stalling halfway?

There's no technically correct answer here, so what matters is the order of operations. An answer that lays out the steps and names the point where this work usually stalls comes from experience, and tells me I'm talking to someone who has done it. An answer that names a tool and the word "gradually" is an intention. A good one looks roughly like this: types at the module boundaries first, then --strict one module at a time, then a CI gate that only fails when the typing got worse.

4. Memory Management

Q: How would you identify and resolve memory leaks in a production application?

Q: You have a memory leak in the working production application on one of your company servers. How would you start debugging it?

Q: You need to process a file that is too large to fit into memory. How would you handle this in Python?

  • Follow-up 1: How can you ensure the solution is memory-efficient and scalable?
  • Follow-up 2: If the file is compressed (e.g., a .gz or .zip file), how would you process it without fully decompressing it in memory?
  • Follow-up 3: How would you adapt your solution if the file is being streamed over a network instead of being locally stored?

Python is Hard

5. Performance and Optimization

Q: How would you profile a Python application to identify performance bottlenecks? What tools or techniques would you use?

Q: What is __pycache__ in Python, and why does Python generate .pyc files? How do they improve performance?

Q: What is string interning? Why does Python use it?

Q: Why doesn't Python support tail recursion optimization? How would you implement a similar effect manually?

Q: You're asked to optimize a Python web application under high load. How would you approach this, and what tools might you use?

Q: What does the PYTHONOPTIMIZE flag do?

Q: What advantages do NumPy arrays offer over (nested) Python lists?

6. Packaging and Distribution

Q: How do you distribute Python code effectively?

Q: How does Python manage binary dependencies? Discuss wheels and eggs.

Q: What are Python's package managers, and which one would you recommend?

Q: How do you handle transitive dependencies in Python projects?

Q: What is Cython, IronPython, and PyPy? Why do these alternate implementations exist?

Q: Explain how to access a Python module from C and vice versa.

7. Functional Programming

Q: Is Python a functional programming language? Explain with examples.

Q: What are the key pitfalls or limitations of writing functional code in Python?

Q: How can you implement functional concepts like immutability or higher-order functions in Python?

8. Concurrency

Q: What is the difference between concurrency and parallelism?

  • Follow-up: Can Python achieve true parallelism? Why or why not?

Q: What is the GIL, and how does it affect concurrency and async programming in Python? How does Python's asyncio handle concurrency despite the GIL?

  • Follow-up: Why did the GIL last as long as it did?

Q: What are sub-interpreters, and how do they differ from threads and from separate processes? When would you pick them over either one?

Since 3.12 each sub-interpreter gets its own GIL, so the parallelism is real. They don't share memory the way threads do, though, and data still has to be passed between them. Against processes you win on startup cost and memory; against threads you win on isolation.

Q: Compare and contrast async programming, multi-threading, and multi-processing in Python.

Q: Imagine a producer thread is generating data faster than a consumer can process it. How would you handle this scenario in Python?

  • Follow-up: How would you handle it in an async setup?

Q: asyncio.TaskGroup and except* arrived in 3.11. How do they change the way you write concurrent code compared to asyncio.gather?

The behaviour here is the opposite of gather, so anyone answering by analogy gets it wrong. That's what I'm checking: either they remember the difference, or they extrapolate from what they knew before. The second layer is what ends up in the handler's hands. If they talk about it in the singular, they've seen except* but never written it.

  • Follow-up: One task in a group raises. What happens to the others, and what do you end up catching?

Q: How do you debug async code effectively? Mention tools or techniques you've used.

Q: What is backpressure in async systems, and how can you handle it?

Q: Discuss how async programming can improve the scalability of a web application.

Q: Write a function using asyncio.Queue to implement a producer-consumer pattern with multiple producers and consumers.

Q: How would you design a high-performance async API server? What frameworks would you use, and why?

Q: How can you integrate async programming with synchronous libraries or codebases?

Q: What are the limitations of async programming in Python, and how would you work around them?

9. Coding Challenges

Q: Give an example of a filter and reduce over an iterable object.

Q: Write a function that reverses the generator?

Q: You need to implement a function that should use a static variable (for example, a call counter). You cannot write any code outside the function and you do not have information about external variables (outside your function). How to do it?

Q: What methods and in what order are called when print (A() + B()) is executed?

Q: How to implement a dictionary from scratch using core Python?

Q: What will be the output of the following code?

>>> a = [[]] * 3
>>> a[1].append(1)
>>> print(a)  # [[1], [1], [1]]

Q: Place the following functions below in order of their efficiency. How would you test your answer?

def f1(arr):
    l1 = sorted(arr)
    l2 = [i for i in l1 if i < 0.5]
    return [i * i for i in l2]
def f2(arr):
    l1 = [i for i in arr if i<0.5]
    l2 = sorted(l1)
    return [i * i for i in l2]
def f3(arr):
    l1 = [i * i for i in arr]
    l2 = sorted(l1)
    return [i for i in l1 if i < (0.5*0.5)]

The answer depends on the data, and that's half the question. The other half is "how would you test that". An answer that names one specific order with no caveat about the data is incomplete, whatever that order happens to be. And whoever gets as far as "I'd measure it" usually goes on to say which inputs they'd measure on.

Q: Write a one-liner that will count the number of capital letters in a file. Your code should work even if the file is too big to fit in memory.

Q: What will be the output of the following code? Why? Is this inheritance?

class C:
    pass

type (C())
type (C)

Q: What will be the output of the following code?

big_num_1   = 1000
big_num_2   = 1000
small_num_1 = 1
small_num_2 = 1
big_num_1 is big_num_2
small_num_1 is small_num_2

Q: How is this possible?

_MangledGlobal__mangled = 23

class MangledGlobal:
     def test(self):
         return __mangled

>>> MangledGlobal().test()
23

Q: You saw the following piece of code. What is wrong with this code? Why is it needed?

if __debug__:
    assert False, ("error")

You may also find python programmer jobs with Jooble

Additional materials

Liked this? I publish one deep-dive every week.

Join 4,000+ engineers. No BS.

Get the newsletter
Previous post
Next post

Enjoyed what you just read? Others like these as well:

Python Interview Questions for Mid-Level Developers

Python Interview Questions for Beginners (Junior)

How Not to Partition Data in S3 (And What to Do Instead)