Career Tips

Python Interview Questions for Mid-Level 2026

JobRise Team21 min read

162 applications per offer, 2026 average.

Python Interview Questions for Mid-Level 2026jobrise.io

Advertisement

You’ve done the beginner grind. You can write Python, ship features, fix bugs, and explain what a list comprehension is without sweating. But mid-level Python interviews in 2026 are a different beast: they test whether you can think like someone who owns code in production.

Companies are not just asking “What is a decorator?” anymore. They want to know how you debug slow APIs, design clean modules, write safe concurrent code, test properly, and talk through tradeoffs like a grown-up engineer.

If you are interviewing for Python roles at places like Spotify, Stripe, Revolut, Shopify, Datadog, Booking.com, Zalando, or fast-growing startups, expect the bar to sit somewhere between “solid developer” and “future senior.”

In the US, mid-level Python developers often see salaries around $105k to $145k, with higher ranges at companies like Meta, Google, Netflix, and Stripe. In Europe, you might see €55k to €85k in cities like Berlin, Amsterdam, Dublin, Madrid, and Paris, with senior-leaning mid-level roles hitting €90k to €110k at stronger tech firms.

So let’s get you ready.

What Mid-Level Python Interviews Actually Test in 2026#

A mid-level Python interview is rarely about memorizing syntax. You are expected to know the language, but the real signal is how you reason.

Most interviews test five things:

  1. Core Python knowledge

    • Data structures
    • Functions and scope
    • Classes and inheritance
    • Iterators and generators
    • Exceptions
    • Type hints
  2. Practical engineering judgment

    • When to write simple code
    • When abstraction helps
    • How to avoid clever messes
    • How to make code readable for the next person
  3. Production awareness

    • Logging
    • Error handling
    • Performance
    • Memory use
    • Testing
    • Observability
  4. Framework knowledge

    • Django
    • FastAPI
    • Flask
    • SQLAlchemy
    • Celery
    • Pytest
  5. System thinking

    • APIs
    • Databases
    • Queues
    • Caching
    • Background jobs
    • Async work

At mid-level, your answers should sound like you have been burned by real code before. Not dramatic, just practical.

A junior answer says: “I would use a dictionary because lookup is O(1).”

A mid-level answer says: “I would use a dictionary if the data fits in memory and keys are stable. If this grows large or needs persistence, I’d probably move it to Redis or a database index.”

That second answer is what interviewers want.

Core Python Interview Questions for Mid-Level Developers#

1. What are Python’s main built-in data structures, and when would you use each?

You should be able to explain:

  • list: ordered, mutable, good for sequences
  • tuple: ordered, immutable, good for fixed records
  • dict: key-value lookup, great for mappings
  • set: unique values, membership checks
  • deque: fast appends and pops from both ends
  • heapq: priority queues
  • Counter: counting items
  • defaultdict: cleaner default values

A good answer sounds like this:

“I’d use a list for ordered data I need to iterate over, a dict for fast lookup by key, and a set when I care about uniqueness or membership. If I’m building a queue, I’d avoid popping from the front of a list because that is O(n). I’d use collections.deque instead.”

That last sentence matters. It shows you know performance without being annoying about it.

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

== checks value equality. is checks object identity.

Example:

a = [1, 2, 3]
b = [1, 2, 3]

a == b  # True
a is b  # False

Use is for singleton checks:

if value is None:
    ...

Do not write:

if value == None:
    ...

The interviewer may ask about small integers or string interning. You can say Python may reuse some immutable objects internally, but you should not depend on that behavior in application code.

3. Explain mutable default arguments.

This is a classic mid-level trap.

Bad code:

def add_item(item, items=[]):
    items.append(item)
    return items

The default list is created once when the function is defined, not every time it is called. So calls share the same list.

Better:

def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

A strong answer includes when this behavior might be intentional, such as caching, but says you would normally avoid it because it surprises people.

4. What are decorators, and when would you use them?

A decorator wraps a function or class to add behavior.

Common uses:

  • Logging
  • Authentication checks
  • Timing
  • Caching
  • Retry logic
  • Validation

Example:

import time
from functools import wraps

def timing(func):
    @wraps(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

Mention functools.wraps. That is a nice mid-level signal because it preserves function metadata.

A strong answer also says decorators can make code harder to debug if overused. Keep them simple and obvious.

5. What are generators, and why use them?

Generators produce values lazily. They are useful when you do not want to load everything into memory.

Example:

def read_lines(path):
    with open(path) as f:
        for line in f:
            yield line.strip()

Use cases:

  • Processing large files
  • Streaming data
  • Pipelines
  • Infinite sequences
  • Memory-sensitive tasks

You can say: “A generator helps when I want iteration without storing the full collection. For example, reading a 5GB log file line by line.”

That is better than just saying “it uses yield.”

6. What is the difference between iterator and iterable?

An iterable is anything you can loop over. An iterator is the object that actually returns the next value.

  • Iterable has __iter__
  • Iterator has __iter__ and __next__

Example:

numbers = [1, 2, 3]
iterator = iter(numbers)
next(iterator)

A list is iterable but not itself an iterator. A generator is both.

Python OOP Questions You Should Expect#

7. How does inheritance work in Python?

Python supports single and multiple inheritance. A class can inherit attributes and methods from a parent class.

Example:

class Animal:
    def speak(self):
        return "sound"

class Dog(Animal):
    def speak(self):
        return "bark"

Mid-level answer: explain that inheritance is useful when there is a real “is-a” relationship. Otherwise, composition may be cleaner.

Good line:

“I try not to build deep inheritance trees in business code. Composition is often easier to test and change.”

Interviewers love that because it sounds like someone who has maintained messy code.

8. What is MRO in Python?

MRO means Method Resolution Order. It is the order Python uses to search for methods in a class hierarchy.

You can inspect it:

MyClass.__mro__

or:

help(MyClass)

Python uses the C3 linearization algorithm. You do not need to explain the algorithm in detail unless asked.

Say this:

“MRO matters most with multiple inheritance. If two parent classes define the same method, Python follows the MRO to decide which method gets called.”

9. What are @staticmethod, @classmethod, and instance methods?

Instance methods receive self. They operate on object state.

Class methods receive cls. They often act as alternative constructors or work with class-level data.

Static methods receive neither self nor cls. They are namespaced helper functions.

Example:

class User:
    def __init__(self, email):
        self.email = email

    @classmethod
    def from_dict(cls, data):
        return cls(data["email"])

    @staticmethod
    def normalize_email(email):
        return email.strip().lower()

A good answer includes judgment:

“If the method needs instance data, use an instance method. If it creates or modifies class-level behavior, use a class method. If it is just related utility logic, static method can be okay, though sometimes a module-level function is clearer.”

Advertisement

Python Performance Interview Questions#

10. How would you make slow Python code faster?

Do not jump straight to “use Cython.” Start with measuring.

Strong answer:

  1. Reproduce the issue
  2. Add logging or metrics
  3. Profile with cProfile, py-spy, or line_profiler
  4. Check database queries
  5. Check network calls
  6. Improve algorithms
  7. Reduce unnecessary allocations
  8. Cache where safe
  9. Move heavy work to background jobs
  10. Consider NumPy, Rust, Go, or C extensions only if needed

Mid-level developers know that slow Python is often not Python’s fault. It is usually bad queries, too many API calls, missing indexes, or loading too much data.

For example:

“If a Django endpoint is slow, I’d check SQL queries first with Django Debug Toolbar or logging. N+1 queries are very common.”

That answer hits reality.

11. What is Big O, and what should Python developers know?

You should know common costs:

  • List append: usually O(1)
  • List insert at front: O(n)
  • Dict lookup: average O(1)
  • Set membership: average O(1)
  • Sorting: O(n log n)
  • Nested loop over same collection: often O(n²)

Interviewers may ask you to optimize code like this:

result = []
for user_id in user_ids:
    if user_id in active_user_ids:
        result.append(user_id)

If active_user_ids is a list, membership is O(n). Convert it to a set:

active = set(active_user_ids)
result = [user_id for user_id in user_ids if user_id in active]

Explain the tradeoff:

“This uses extra memory for the set, but makes lookup much faster for large inputs.”

12. What is the GIL?

The GIL, or Global Interpreter Lock, allows only one thread to execute Python bytecode at a time in CPython.

Practical impact:

  • Threads can help with I/O-bound tasks
  • Threads usually do not speed up CPU-bound Python code
  • Multiprocessing can help CPU-bound work
  • Async can help high-concurrency I/O
  • Native extensions may release the GIL

Good answer:

“If I’m calling APIs or waiting on database responses, threads can still help because most time is spent waiting. If I’m doing CPU-heavy image processing or data crunching, I’d look at multiprocessing, NumPy, or moving that work outside the request path.”

In 2026, you may also get asked about free-threaded Python builds. You can say CPython has been moving toward optional no-GIL builds, but many production stacks still need compatibility testing before depending on that.

That is a safe, current answer.

13. When would you use multiprocessing?

Use multiprocessing for CPU-bound tasks where separate processes can run in parallel.

Examples:

  • Image processing
  • Large file transformations
  • Batch calculations
  • Data parsing
  • ML preprocessing

Watch out for:

  • Serialization cost
  • Memory overhead
  • Process startup time
  • Shared state complexity
  • Debugging difficulty

Good phrase:

“I’d use multiprocessing when the work is large enough to justify the overhead and can be split into independent chunks.”

Async Python Interview Questions#

14. What problem does asyncio solve?

asyncio helps manage many I/O-bound tasks concurrently using an event loop.

Good examples:

  • Calling many APIs
  • WebSocket connections
  • Async web servers
  • Chat systems
  • Crawlers
  • Queue consumers

Basic example:

import asyncio
import httpx

async def fetch(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.text

async def main():
    pages = await asyncio.gather(
        fetch("https://example.com"),
        fetch("https://example.org"),
    )

The key point:

“Async does not make CPU code faster. It helps when tasks spend time waiting.”

15. What is the difference between concurrency and parallelism?

Concurrency means handling multiple tasks in overlapping time. Parallelism means doing multiple tasks at the same exact time.

A nice answer:

“Async Python gives concurrency on one thread. Multiprocessing gives parallelism across CPU cores.”

Simple. Clean. Interviewer happy.

16. What mistakes happen in async Python?

Common mistakes:

  1. Forgetting await
  2. Blocking the event loop with CPU work
  3. Using sync libraries inside async code
  4. Creating too many tasks without limits
  5. Not handling cancellation
  6. Not setting timeouts
  7. Sharing mutable state badly

Example bad idea:

time.sleep(5)

Inside async code, use:

await asyncio.sleep(5)

For external calls, set timeouts. Mid-level developers mention timeouts because production systems die slowly without them.

Django, FastAPI, and Web Interview Questions#

17. Django vs FastAPI: when would you choose each?

Django is great when you want batteries included:

  • ORM
  • Admin panel
  • Authentication
  • Forms
  • Migrations
  • Security defaults

FastAPI is great when you want:

  • API-first services
  • Async support
  • Pydantic validation
  • OpenAPI docs
  • Lightweight structure
  • Fast development for microservices

Good answer:

“I’d pick Django for a product with admin workflows, relational data, and built-in auth needs. I’d pick FastAPI for a focused API service where request validation and OpenAPI docs matter a lot.”

Mention company style if useful. Instagram has famously used Django at massive scale. FastAPI is common across startups and API-heavy teams because it is quick and clean.

18. How do you prevent N+1 queries in Django?

N+1 happens when code does one query for a list, then one extra query per item.

Example bad pattern:

posts = Post.objects.all()
for post in posts:
    print(post.author.name)

Fix with:

posts = Post.objects.select_related("author").all()

Use:

  • select_related for foreign key and one-to-one
  • prefetch_related for many-to-many and reverse relationships

Also mention:

  • Add indexes where needed
  • Inspect queries
  • Avoid loading unused fields
  • Paginate large lists

19. How does FastAPI validation work?

FastAPI uses type hints and Pydantic models to validate and serialize data.

Example:

from pydantic import BaseModel

class UserCreate(BaseModel):
    email: str
    age: int

FastAPI can:

  • Validate request bodies
  • Generate OpenAPI docs
  • Serialize responses
  • Return clear validation errors

In 2026, many teams are using Pydantic v2. You do not need to recite every change, but you should know validation models are central to FastAPI.

Testing Questions for Mid-Level Python Roles#

20. How do you test Python code?

A strong answer mentions layers:

  1. Unit tests for isolated logic
  2. Integration tests for database and service interactions
  3. API tests for endpoints
  4. Contract tests where services depend on each other
  5. End-to-end tests for critical flows

Tools:

  • pytest
  • unittest
  • coverage.py
  • factory_boy
  • freezegun
  • responses
  • pytest-mock
  • hypothesis

Good answer:

“I prefer testing behavior, not implementation details. If I refactor internal code and tests break even though behavior is the same, the tests may be too tightly coupled.”

That is a very mid-level thing to say.

21. What makes a good unit test?

Good unit tests are:

  • Fast
  • Deterministic
  • Easy to read
  • Focused on one behavior
  • Clear when they fail

Example structure:

def test_discount_applies_for_premium_user():
    user = User(plan="premium")
    price = calculate_price(user, base_price=100)

    assert price == 80

Avoid tests that need five mocks and a prayer. If a unit test is painful to write, your code may be too coupled.

22. How do you mock external services?

You can use mocks or fake services. For HTTP calls, tools like responses or respx are common.

Good answer:

“I mock external APIs in unit tests so tests are fast and stable. For integration tests, I may use a sandbox environment or a local fake service if the contract matters.”

Also mention that you do not want tests failing because Stripe, Twilio, or SendGrid had a temporary issue.

Advertisement

Database and API Design Questions#

23. How do you design a REST API endpoint?

Talk through:

  1. Resource naming
  2. HTTP methods
  3. Request validation
  4. Authentication
  5. Authorization
  6. Pagination
  7. Filtering and sorting
  8. Status codes
  9. Error format
  10. Rate limits
  11. Idempotency where needed

Example:

GET /api/users?page=2&status=active
POST /api/users
GET /api/users/\{id\}
PATCH /api/users/\{id\}
DELETE /api/users/\{id\}

For payments or order creation, mention idempotency keys. Companies like Stripe care deeply about this, and many interviewers love hearing it.

24. What status codes should you know?

Know the practical ones:

  • 200: OK
  • 201: Created
  • 204: No Content
  • 400: Bad Request
  • 401: Not authenticated
  • 403: Authenticated but not allowed
  • 404: Not found
  • 409: Conflict
  • 422: Validation error, common in FastAPI
  • 429: Rate limited
  • 500: Server error

A mid-level answer includes consistency:

“I’d make sure errors have a consistent structure so frontend and API clients can handle them cleanly.”

25. How would you handle database transactions?

Use transactions when multiple database changes must succeed or fail together.

Example:

from django.db import transaction

with transaction.atomic():
    order = Order.objects.create(user=user)
    Payment.objects.create(order=order, amount=total)

Mention:

  • Keep transactions short
  • Avoid slow network calls inside transactions
  • Handle retries for deadlocks where appropriate
  • Think about isolation levels for sensitive workflows

Good phrase:

“I would not call an external payment provider inside a long database transaction if I can avoid it. I’d separate the steps and use clear state transitions.”

Error Handling and Logging Questions#

26. How do you handle exceptions in Python?

Use specific exceptions where possible.

Bad:

try:
    process()
except Exception:
    pass

Better:

try:
    process()
except PaymentDeclined as exc:
    logger.info("Payment declined", extra={"reason": str(exc)})
    raise

Good answer:

“I avoid swallowing exceptions unless I have a clear fallback. If I catch an exception, I either handle it, add context and re-raise it, or return a controlled error.”

27. What should you log?

Log events that help debug production issues:

  • Request IDs
  • User or account IDs where safe
  • Job IDs
  • External service response codes
  • Timing
  • State changes
  • Error context

Avoid:

  • Passwords
  • API keys
  • Full credit card data
  • Sensitive personal data
  • Huge payloads

You can say:

“I want logs to answer what happened, to whom, and where, without leaking private data.”

That is a clean production-minded answer.

Clean Code and Architecture Questions#

28. How do you structure a Python project?

For a small FastAPI service:

app/
  main.py
  api/
  models/
  schemas/
  services/
  repositories/
  tests/

For Django, you may organize by apps:

users/
orders/
payments/
notifications/

Good answer:

“I prefer structure that matches the domain and keeps business logic out of views or route handlers. Controllers should be thin. The important logic should be testable without running the whole web app.”

29. What are type hints good for?

Type hints help:

  • Improve readability
  • Catch errors earlier
  • Improve editor support
  • Document expected inputs and outputs
  • Support tools like mypy and pyright

Example:

def calculate_total(prices: list[float]) -> float:
    return sum(prices)

Good answer:

“Type hints do not make Python statically typed at runtime by default, but they help teams maintain larger codebases.”

Mention that type hints are very common now in mid-level and senior Python roles, especially with FastAPI.

30. How do you review Python code?

Strong review checklist:

  1. Is the code clear?
  2. Are edge cases handled?
  3. Are tests meaningful?
  4. Are database queries reasonable?
  5. Are errors handled safely?
  6. Is logging useful?
  7. Is there unnecessary abstraction?
  8. Is performance acceptable?
  9. Is security considered?
  10. Will this be maintainable in six months?

A good interview answer:

“I try to review for correctness first, then readability and maintainability. I avoid style nitpicks if tooling can handle them.”

Behavioral Questions for Mid-Level Python Interviews#

31. Tell me about a production bug you fixed.

Use this format:

  1. Situation
  2. Impact
  3. Investigation
  4. Fix
  5. Prevention

Example answer:

“We had an API endpoint timing out during peak traffic. I checked logs and saw response time spiking only on one list endpoint. Query logging showed an N+1 issue that loaded customer records inside a loop. I fixed it with select_related, added a regression test, and added basic query count monitoring for that view.”

That sounds real. It has impact, debugging, fix, and prevention.

32. Tell me about a technical disagreement.

Do not say everyone was wrong and you saved the company. That sounds exhausting.

Better:

“We disagreed about adding a shared abstraction for multiple integrations. I felt the abstraction was too early because only two integrations existed and their behavior was different. I suggested keeping shared helper functions first, then revisiting after the third integration. We did that, and the final abstraction was much cleaner.”

This shows judgment and teamwork.

33. How do you handle unclear requirements?

Good answer:

“I ask questions, write down assumptions, and try to create a small version first. If the risk is high, I confirm behavior with product or stakeholders before building too much.”

Mid-level developers are expected to protect the team from wasted work.

Coding Exercise Questions You Might See#

34. Find the first non-repeating character.

from collections import Counter

def first_unique_char(text: str) -> str | None:
    counts = Counter(text)
    for char in text:
        if counts[char] == 1:
            return char
    return None

Explain:

  • First pass counts characters
  • Second pass preserves order
  • Time is O(n)
  • Space is O(k), where k is unique characters

35. Merge intervals.

def merge_intervals(intervals: list[tuple[int, int]]) -> list[tuple[int, int]]:
    if not intervals:
        return []

    intervals.sort()
    merged = [intervals[0]]

    for start, end in intervals[1:]:
        last_start, last_end = merged[-1]

        if start ≤ last_end:
            merged[-1] = (last_start, max(last_end, end))
        else:
            merged.append((start, end))

    return merged

Explain sorting cost: O(n log n). The scan is O(n).

36. Rate limiter design question.

You may be asked: “How would you rate limit API requests?”

Simple answer:

  • Use Redis
  • Store count per user or IP
  • Set expiration window
  • Return 429 when limit is exceeded

Example design:

key = rate_limit:\{user_id\}:\{minute\}
INCR key
EXPIRE key 60

Better answer includes tradeoffs:

“A fixed window is simple but can allow bursts at boundaries. A sliding window or token bucket is smoother but more complex.”

That is mid-level gold.

Questions You Should Ask the Interviewer#

Do not end with “No questions from me.” Ask smart, practical questions.

Try these:

  1. “What does success look like for this role after six months?”
  2. “What are the biggest technical problems the Python team is dealing with?”
  3. “How much of the work is new feature development vs maintenance?”
  4. “What Python frameworks are used most here?”
  5. “How do you handle testing and code review?”
  6. “Are engineers expected to be on call?”
  7. “What is the deployment process like?”
  8. “How does the team measure production health?”
  9. “What would make someone struggle in this role?”
  10. “What salary range is budgeted for this position?”

That last one is fair. If a US company is hiring a mid-level Python developer for $95k, and your target is $130k, you need to know early. In Europe, if the role is €60k in Amsterdam or Dublin, ask about total compensation, remote policy, pension, bonus, and equity.

How to Prepare in 7 Days#

If your interview is soon, here is a practical plan.

Day 1: Core Python

Review:

  • Lists, dicts, sets, tuples
  • Mutability
  • Scope
  • Decorators
  • Generators
  • Exceptions

Write small examples by hand.

Day 2: Algorithms

Practice:

  • Hash maps
  • Two pointers
  • Sorting
  • Stacks and queues
  • Basic recursion
  • String parsing

Do not grind 200 LeetCode questions. For mid-level Python roles, quality beats panic.

Day 3: Web Frameworks

Review the framework in the job description.

For Django:

  • ORM
  • Migrations
  • Middleware
  • Query optimization
  • Auth
  • Transactions

For FastAPI:

  • Pydantic
  • Dependency injection
  • Async endpoints
  • Response models
  • OpenAPI docs

Day 4: Databases and APIs

Review:

  • Indexes
  • Joins
  • Transactions
  • Pagination
  • REST status codes
  • Idempotency
  • Caching

Day 5: Testing

Practice writing tests with pytest.

Focus on:

  • Fixtures
  • Mocking
  • Parametrize
  • Testing exceptions
  • Testing APIs
  • Coverage basics

Day 6: System Design Lite

Prepare for small design questions:

  • URL shortener
  • Rate limiter
  • Background email worker
  • File upload service
  • Notification system
  • Analytics event collector

At mid-level, they do not expect Staff Engineer architecture. They expect sane tradeoffs.

Day 7: Stories and Resume

Prepare five stories:

  1. Bug you fixed
  2. Feature you shipped
  3. Performance improvement
  4. Conflict or disagreement
  5. Time you learned something fast

Tie each story to business impact. “Reduced endpoint response time from 2.8s to 400ms” is much better than “optimized API.”

Final Checklist Before the Interview#

Use this quick checklist the night before:

  • Can you explain your last project clearly?
  • Can you talk about one hard bug?
  • Can you write Python without autocomplete?
  • Can you explain decorators and generators?
  • Can you discuss async vs threads vs multiprocessing?
  • Can you spot N+1 queries?
  • Can you write a few pytest tests?
  • Can you explain one API design?
  • Can you ask about salary without sounding awkward?
  • Can you explain tradeoffs instead of pretending every choice is obvious?

That last point is the big one.

Mid-level interviews are not about having a perfect answer. They are about showing that you can make reasonable decisions, communicate clearly, and keep production code healthy.

If you want one easy win before applying, run your resume through a checker and make sure it actually matches Python jobs before a recruiter sees it. Try the free JobRise ATS checker here: https://jobrise.io/en/free-ats-checker/

Advertisement

Advertisement

Send this to whoever has the interview this week.

Advertisement

Advertisement