Python Interview Questions and Answers — STAR Format Guide for 4+ Years Experience (2026)
February 26, 2026 Updated • By Surya Singh • Python • Django • FastAPI • Interview • Backend
Key Takeaways
- 110 in-depth Python STAR answers with real production scenarios, metrics, and what separates good from great
- 2Covers generators, decorators, GIL, data structures, OOP, error handling, pytest, Django/FastAPI, data processing, packaging
- 33 rapid-fire rounds (Core, Advanced, Production) with 10+ practice STAR answers
- 4E-E-A-T experience block, 8 common mistakes, 8 FAQs, and links to MERN, MEAN, SQL, AI/ML, System Design guides
This guide targets Python backend engineers and full-stack developers preparing for senior roles. Every answer uses the STAR method with production scenarios—real problems, concrete actions, and measurable outcomes. Topics span generators and iterators, decorators (caching, retry, auth), GIL and concurrency, data structures, OOP (abstract classes, mixins, dataclasses), error handling, pytest, Django vs FastAPI, data processing, and packaging/deployment.
Answers reference the Python documentation, pytest docs, and the FastAPI documentation.
Table of Contents
- 1. Generators and Iterators — Processing Large Datasets
- 2. Decorators — Caching, Retry, Auth, Logging
- 3. GIL and Concurrency — Threading vs Multiprocessing vs Asyncio
- 4. Data Structures — list, tuple, set, dict, deque, defaultdict, Counter
- 5. OOP — Abstract Classes, Mixins, Dataclasses, __slots__
- 6. Error Handling — Exceptions, Context Managers, Logging
- 7. Testing with pytest — Fixtures, Parametrize, Mocking
- 8. Web Frameworks — Django vs FastAPI Trade-offs
- 9. Data Processing — pandas, numpy, Memory Profiling
- 10. Packaging and Deployment — venv, Poetry, Docker, CI/CD
- Rapid-Fire Practice (3 Rounds)
- From Real Experience
- Common Mistakes to Avoid
- FAQ (8 Questions)
- Related Interview Guides
1) How do you use generators and iterators for processing large datasets?
What interviewer evaluates: Understanding of lazy evaluation, memory efficiency, and when generators beat lists.
Situation: A data pipeline processed a 12GB log file to extract unique IP addresses. The original approach read the entire file into a list, then deduplicated. Peak memory hit 8GB; the process was killed by OOM on 4GB machines.
Task: Process the file with constant memory regardless of size.
Action:
- Generator for line-by-line: Wrote a generator that yielded one line at a time. No list materialization—each line was processed and discarded before the next.
- Streaming deduplication: Used a set for O(1) membership. Generator yielded lines; each IP was added to the set only if not seen. Set grew with unique IPs (much smaller than total lines).
- Chunked reading: For binary files, used
readwith a fixed chunk size in a generator loop. Same memory profile regardless of file size. - Iterator protocol: Implemented
__iter__and__next__for a custom class when we needed stateful iteration with cleanup. Generator functions were simpler for most cases. - itertools for pipelines: Used
itertools.islice,itertools.filterfalsefor composable lazy pipelines. Avoided materializing intermediate lists.
Result: Peak memory dropped from 8GB to 180MB. The same pipeline ran on 2GB machines. Processing time increased 15% (no batching) but the system became deployable on cheaper infrastructure.
What separates good from great: Explain the iterator protocol, when to use yield vs return, and the memory trade-off. Mention itertools for composition.
2) How do you implement decorators for caching, retry, auth, and logging?
What interviewer evaluates: Decorator mechanics, functools.wraps, and practical use cases.
Situation: A service called three third-party APIs. One had 5% failure rate and random timeouts. Manual retry logic was duplicated in 12 places. Another function computed expensive aggregations—called 1000 times per request with the same arguments.
Task: Centralize retry logic and add caching for the expensive function.
Action:
- @retry decorator: Built a decorator that wrapped the function, caught specific exceptions, retried with exponential backoff. Parameters:
max_attempts,exceptions,backoff. Usedfunctools.wrapsto preserve__name__and docstring. - @cache decorator: Used
functools.lru_cachefor the aggregation function. Arguments must be hashable. Setmaxsizeto limit memory. For non-hashable args, built a custom decorator that used a dict keyed bystr(args)with TTL. - @require_auth: Decorator that checked request headers or context, raised 401 if missing. Applied to route handlers. Composable:
@require_auththen@retry. - @log_call: Decorator that logged function name, args (sanitized), and duration. Used for debugging slow endpoints. Avoided logging sensitive data.
- Decorator with args: For
@retry(max_attempts=5), used a decorator factory: outer function takes args, returns the actual decorator that receives the wrapped function.
Result: API failure handling improved—transient errors retried automatically; permanent failures surfaced faster. Aggregation latency dropped 90% (cache hit rate 85%). Retry and cache logic lived in one place.
What separates good from great: Explain decorator as a function that takes a function and returns a function. Show functools.wraps. Mention decorator factories for parameterized decorators.
Loading...
3) How do you choose between threading, multiprocessing, and asyncio for concurrency?
What interviewer evaluates: GIL awareness, I/O-bound vs CPU-bound, and when each model fits.
Situation: A dashboard aggregated data from 20 REST APIs. Sequential calls took 8 seconds. A colleague used multiprocessing.Pool—overhead was high, and the process count exploded. Another used threads—sometimes worked, sometimes slower than sequential.
Task: Reduce aggregate latency to under 1 second with correct concurrency model.
Action:
- GIL and I/O: The GIL prevents true CPU parallelism in threads, but it is released during I/O (network, file). All 20 calls were I/O-bound—threading was appropriate. Explained to the team: threads work for I/O; multiprocessing is for CPU-bound.
- ThreadPoolExecutor: Used
concurrent.futures.ThreadPoolExecutorwithmax_workers=20. Submitted all 20 requests;as_completedcollected results. Single-threaded bottleneck removed. - Asyncio alternative: Rewrote with
asyncioandaiohttpfor the same use case. Single thread, 20 concurrent coroutines. Slightly lower latency (no thread context switching) and scaled to 100+ concurrent calls. - When multiprocessing: A separate pipeline did heavy Pandas/NumPy work. Used
multiprocessing.Poolwith one process per CPU core. Each process had its own GIL—real parallelism for CPU. - Mixing: For a hybrid app (API calls + CPU work), used asyncio for I/O;
run_in_executorwith ThreadPoolExecutor for blocking library calls. Kept CPU-heavy work in a separate process pool.
Result: Dashboard load time: 8s to 0.9s with threading. Migrated to asyncio for 40 endpoints—0.6s. CPU pipeline used 4 processes; throughput 4x. Zero confusion about when to use which.
What separates good from great: Explain GIL, I/O-bound vs CPU-bound, and the trade-offs. Show you know asyncio for many concurrent I/O operations.
4) How do you choose and use list, tuple, set, dict, deque, defaultdict, and Counter?
What interviewer evaluates: Time complexity, immutability, hashability, and practical selection.
Situation: A real-time order-processing system had a queue implemented as a list with pop(0)—every dequeue was O(n) because it shifted all elements. Another module built a frequency map with a dict and manual d.get(k, 0) + 1 in 50 places.
Task: Fix performance and reduce boilerplate.
Action:
- deque for queue: Replaced list with
collections.deque.appendandpopleftare O(1). No shifting. FIFO queue behaviour correct. - Counter for frequency: Replaced manual dict logic with
Counter.Counter(iterable)orc[key] += 1.most_common(n)for top-N. 50 call sites simplified to one pattern. - defaultdict for accumulation: When building a dict of lists (e.g. group by key), used
defaultdict(list). Noif k not in d: d[k] = []—automatic initialization. - set for membership: Replaced
if x in list_of_10000withif x in set_of_10000. O(1) vs O(n). Used for deduplication and fast lookup. - tuple for keys: When a composite key was needed (e.g.
(tenant_id, date)), used tuple—hashable and immutable. List cannot be a dict key.
Result: Dequeue latency dropped from 15ms to 0.01ms at 10K items. Frequency logic reduced by 120 lines. Code review established defaultdict and Counter as standard patterns.
What separates good from great: Know O(1) vs O(n) for common operations. Explain when tuple beats list (immutability, hashability). Mention deque and Counter by name.
5) How do you use abstract classes, mixins, dataclasses, and __slots__?
What interviewer evaluates: OOP patterns, when to use each, and memory awareness.
Situation: A payment system had 4 payment providers (Stripe, PayPal, bank transfer, crypto). Each had different init params and methods. A new provider required copying 80 lines and changing 15 places. Instance count was 10K per process—memory was a concern.
Task: Unify the interface, reduce duplication, and cut memory per instance.
Action:
- Abstract base class: Defined
PaymentProviderwithabc.ABCand abstract methodscharge,refund,get_status. Each provider implemented the interface. New providers had a clear contract. - Mixins for cross-cutting:
LoggingMixinadded logging to any provider.RetryMixinadded retry logic. Composed:class StripeProvider(LoggingMixin, RetryMixin, PaymentProvider). Single inheritance for core; mixins for behaviour. - Dataclasses for config: Provider config (api_key, timeout, etc.) was a dataclass.
@dataclassgave__init__,__eq__, repr for free. Frozen for immutability. Type hints for clarity. - __slots__ for memory: Each provider instance had 5–8 attributes, no dynamic attributes. Added
__slots__ = ['api_key', 'timeout', ...]. Memory per instance dropped 40% (no__dict__). Critical for 10K instances. - Protocol for structural typing: For functions that only needed
charge, usedtyping.Protocol—duck typing with type checking. No inheritance required.
Result: New provider addition: 80 lines to 25. Memory per process dropped 35%. Type checker caught 3 interface violations. Mixins reused across 6 classes.
What separates good from great: Explain ABC for interface enforcement, mixins for composition, dataclasses for boilerplate reduction, __slots__ for memory. Mention Protocol for structural typing.
Loading...
6) How do you handle errors with exceptions, context managers, and logging?
What interviewer evaluates: Exception hierarchy, custom exceptions, context managers, and structured logging.
Situation: A data import job failed midway—partial DB state, no rollback. Logs showed "Error" with no context. Another service swallowed exceptions with bare except, hiding bugs for weeks.
Task: Implement robust error handling and observable failures.
Action:
- Custom exceptions: Created
ValidationError,ExternalAPIError,RetryableErrorinheriting from appropriate base. Callers caught specific types; retry logic caught onlyRetryableError. - Context manager for transactions:
with db.transaction():that committed on success, rolled back on exception. Ensured all-or-nothing. Usedcontextlib.contextmanagerfor simple cases. - Resource cleanup: File handles and connections in context managers:
with open(...) as f,with pool.connection() as conn. Guaranteed cleanup on exception or early return. - Structured logging: Replaced print with
logging. Usedlogger.exceptionin except blocks to capture traceback. Added context: request_id, user_id, operation. JSON format for log aggregation. - Avoid bare except: Caught
Exceptiononly at top-level handlers. Re-raised after logging. Never caughtBaseException(includes KeyboardInterrupt).
Result: Zero partial imports—all rolled back on failure. Production errors had full context and tracebacks. One swallowed exception discovered and fixed in code review.
What separates good from great: Explain exception chaining, when to use raise from, and context manager protocol. Show structured logging with context.
7) How do you test with pytest — fixtures, parametrize, and mocking?
What interviewer evaluates: Test structure, fixture scope, parametrization, and isolation.
Situation: Tests depended on a real database—flaky, slow, and not runnable in CI. A price calculator had 20 edge cases tested with copy-pasted test functions. Adding a new case required touching 4 files.
Task: Fast, reliable, isolated tests with minimal duplication.
Action:
- Fixtures for setup:
@pytest.fixturefor DB session—created per test, rolled back in teardown.sessionscope for read-only data. Usedconftest.pyfor shared fixtures across modules. - Parametrize for data-driven tests: One test function, multiple inputs:
@pytest.mark.parametrize('price,tax,expected', [(100, 0.1, 110), (0, 0.1, 0), (-1, 0.1, None)]). Added 12 edge cases by adding rows, not new functions. - Mocking external services:
unittest.mock.patchorpytest-mockfor API calls. Patched at the point of use. Asserted call count and args. No real HTTP in tests. - pytest.raises: For exception tests:
with pytest.raises(ValidationError) as exc_info:. Asserted exception message and attributes. - CI integration: pytest in GitHub Actions. Coverage with
pytest-cov. Fail on coverage drop. Parallel withpytest-xdistfor speed.
Result: Test suite: 12 min to 90 seconds. Zero flakiness. New edge case: one line in parametrize. Coverage 85%.
What separates good from great: Explain fixture scope and dependency injection. Show parametrize for multiple inputs. Mention patch placement and assert_called_with.
8) How do you compare Django vs FastAPI and when would you use each?
What interviewer evaluates: Framework trade-offs, async support, and pragmatic selection.
Situation: A startup needed an admin panel, auth, and a public API. Team debated Django vs FastAPI. Django felt heavy for "just an API"; FastAPI had no admin. A legacy Django app needed a high-throughput webhook endpoint.
Task: Choose the right tool and optimize the webhook.
Action:
- Django for full applications: Chose Django for the main app—admin, auth, migrations, ORM out of the box. Development speed high. Team familiar with it. Best when you need CRUD, admin, and conventions.
- FastAPI for APIs: Used FastAPI for the public API—async-native, Pydantic validation, auto OpenAPI. Better performance for I/O-bound endpoints. Type hints and validation reduced bugs.
- Webhook in FastAPI: The high-volume webhook moved from Django to a separate FastAPI service. Async handlers, no blocking. 10x higher req/s on same hardware. Django continued for admin and background jobs.
- When to mix: Monolith vs microservices—Django can serve both admin and API if load is modest. Split when API needs independent scaling or different deployment.
- Trade-offs summarized: Django: batteries-included, sync by default, mature ecosystem. FastAPI: async-first, validation, OpenAPI, smaller footprint for API-only.
Result: Main app on Django—2 weeks to MVP. Webhook on FastAPI—latency P99: 800ms to 45ms. Clear decision framework for future services.
What separates good from great: Present the decision framework: Django for full apps and admin; FastAPI for high-throughput APIs. Mention async and validation.
Loading...
9) How do you process data with pandas and numpy, and profile memory?
What interviewer evaluates: pandas/numpy usage, vectorization, and memory awareness.
Situation: A daily ETL job processed 2M rows. Runtime grew from 5 minutes to 45 minutes over 6 months. Memory usage peaked at 16GB; the job was killed on 8GB machines. The code used Python loops over rows.
Task: Speed up the job and reduce memory to run on 8GB.
Action:
- Vectorization with pandas: Replaced row-wise
applywith vectorized operations:df['new'] = df['a'] + df['b'],df.groupby('key').agg(...). 50x faster. Avoided Python loops over rows. - Numpy for numeric heavy work: Moved matrix operations to numpy—dot products, aggregations. 100x faster than pure Python. Used
np.where,np.selectfor conditional logic. - Memory profiling: Used
memory_profilerortracemallocto find allocations. Found that intermediate DataFrames were kept—chained operations without releasing. - Chunked processing: For the full dataset, used
pd.read_csv(chunksize=50000). Processed chunk by chunk, aggregated results. Peak memory capped by chunk size. - Dtype optimization: Changed
int64toint32oruint8where range allowed. Changed object columns to category for low-cardinality. Memory dropped 40%.
Result: Runtime: 45 min to 4 min. Peak memory: 16GB to 3GB. Job ran on 8GB instances. Vectorization and chunking were the main wins.
What separates good from great: Explain vectorization vs loops, chunked processing for large files, and dtype optimization. Mention memory_profiler or tracemalloc.
10) How do you manage packaging, venv, Poetry, Docker, and CI/CD?
What interviewer evaluates: Dependency management, reproducibility, and deployment practices.
Situation: "Works on my machine" failures—different dependency versions across dev, staging, prod. One deploy overwrote a transitive dependency; production broke. No automated tests before release.
Task: Reproducible builds and safe deployments.
Action:
- Poetry for dependencies: Migrated from pip + requirements.txt to Poetry.
pyproject.tomlfor project config;poetry.lockfor exact versions.poetry installreproduced identical env. Added dev dependencies separately. - venv per project: Each project had its own venv. No global package pollution. CI created a fresh venv, installed from lock file.
- Docker for deployment: Multi-stage build: build stage with Poetry, runtime stage with minimal image (slim base). Copy only wheel and deps. Image size under 200MB.
- CI pipeline: Lint (ruff), format (black), type-check (mypy), test (pytest), security scan (safety). All must pass before merge. Build Docker image on main; push to registry.
- Pre-commit hooks: ruff, black, mypy in pre-commit. Caught issues before push. Same tools as CI—no surprises.
Result: Zero "works on my machine" incidents. Production matches CI environment. Deployment time: 15 min to 3 min with cached layers.
What separates good from great: Explain lock files, multi-stage Docker, and CI steps. Mention mypy and security scanning.
Rapid-fire interview practice — STAR answers
60-second verbal answers. Practice out loud.
Round 1: Core (list vs generator, walrus operator, f-strings, type hints)
Q: When do you use a list vs a generator?
Situation: Processing 1M records from a DB. Loading all into a list exhausted memory.
Task: Process in constant memory.
Action: Used a generator that yielded rows with a server-side cursor. One row at a time; no full materialization. List when you need random access, multiple passes, or small data.
Result: Peak memory 50MB vs 2GB. Generator was the right tool for streaming.
Q: What is the walrus operator and when do you use it?
Situation: A loop needed to assign and check in the same expression.
Task: Simplify the pattern.
Action: := assigns and returns the value. Example: while (line := f.readline()): process(line). Avoids redundant read or extra variable. Use when you need the value in both the condition and the body.
Result: Cleaner loops. Reduced duplicated calls.
Q: How do f-strings improve over format or %?
Situation: Log messages and error strings used .format() with positional args—hard to read.
Task: Improve readability and performance.
Action: F-strings embed expressions: f"User {user_id} failed after {attempts} attempts". No separate format call. Faster (parsed at compile time). Support = for debug: f"{x=}" prints "x=5".
Result: Logs easier to read. Slight perf gain in hot paths.
Q: How do you use type hints in production?
Situation: Large codebase, no types—refactors caused runtime errors.
Task: Add types for safety and tooling.
Action: Gradual typing: new code fully typed. Added types to critical paths. Used mypy in CI. typing.List, Dict, Optional, Union. TypedDict for structured dicts. Generic types for containers.
Result: mypy caught 20+ bugs before merge. IDE autocomplete improved.
Round 2: Advanced (metaclasses, __new__ vs __init__, weakref)
Q: When would you use a metaclass?
Situation: Needed to auto-register all subclasses of a base.
Task: Hook into class creation.
Action: Metaclass __new__ runs when the class is defined. Added each new class to a registry. Rare need—consider simpler alternatives (decorator, explicit registration). Metaclasses control class creation, not instance creation.
Result: Plugin system without manual registration. Documented when to prefer simpler patterns.
Q: What is the difference between __new__ and __init__?
Situation: Needed to implement a singleton or control instance creation.
Task: Understand object lifecycle.
Action: __new__ creates the object (returns the instance); __init__ initializes it. __new__ runs first. Use __new__ for immutable types, singletons, or returning a different class. Most classes only need __init__.
Result: Correct singleton pattern. Understood when each runs.
Q: When do you use weakref?
Situation: A cache held strong references—objects never freed, memory grew.
Task: Allow garbage collection when no one else needs the object.
Action: weakref.ref(obj) or WeakValueDictionary. When the last strong reference is gone, the object can be collected. Cache entries disappear automatically. Use for caches, observers, circular refs.
Result: Cache size bounded by actual use. Memory under control.
Q: How does the MRO (method resolution order) work?
Situation: Diamond inheritance caused unexpected method calls.
Task: Understand and fix resolution order.
Action: MRO is C3 linearization—depth-first, left-to-right, no duplicate. ClassName.mro() shows the order. Ensures each ancestor appears once and subclass before superclass. Explains why super() calls the "next" in MRO, not necessarily the parent.
Result: Correct multiple inheritance. No more mystery method calls.
Round 3: Production (profiling, logging, security)
Q: How do you profile a slow Python application?
Situation: API endpoint took 3 seconds; unknown bottleneck.
Task: Find and fix the slowdown.
Action: cProfile for CPU: python -m cProfile -s cumtime script.py. Identified hot functions. For async, used py-spy or aiohttp debug. memory_profiler for memory. Line-level with line_profiler for critical loops.
Result: Found N+1 DB query—fixed with batch load. Latency 3s to 0.2s.
Q: How do you structure logging for production?
Situation: Logs were inconsistent; traceability across services was hard.
Task: Structured, searchable logs.
Action: JSON format: {"timestamp": "...", "level": "INFO", "msg": "...", "request_id": "..."}. Added request_id to context; propagated across async tasks. Log levels: DEBUG dev only, INFO for events, WARNING for recoverable, ERROR for failures. Never log secrets.
Result: Log aggregation (ELK, Datadog) indexed by request_id. Full request trace in one query.
Q: What Python security pitfalls should you avoid?
Situation: User input was passed to eval(); a code injection was reported.
Task: Harden the application.
Action: Never eval/exec user input. Use ast.literal_eval for safe literals. Parameterized queries for SQL—never string format. Validate and sanitize input. Keep dependencies updated (safety, pip-audit). Avoid pickle from untrusted source. Use secrets for tokens.
Result: Removed eval; used JSON parsing. No further injection reports.
Q: How do you handle secrets in Python apps?
Situation: API keys were in config files—committed to git once.
Task: Secure secret management.
Action: Environment variables or secret manager (Vault, AWS Secrets). Never in code or config in repo. Load at runtime. In Docker: inject via env or mount. Use python-dotenv for local only—never in prod. Rotate keys after incident.
Result: Zero secrets in repo. Rotation procedure documented.
Loading...
From real experience
"I've conducted hundreds of Python and backend interviews. The candidates who stand out don't just know syntax—they explain generators with a memory story, implement a retry decorator on a whiteboard, and know when threading beats multiprocessing. They've fixed a production memory leak with tracemalloc, refactored a 45-minute ETL to 4 minutes with vectorization, and chosen Django vs FastAPI based on the problem."
"At 4+ years, interviewers expect STAR answers with metrics: peak memory dropped from X to Y, latency improved by Z%. If you haven't lived these, study these answers and practice out loud. The GIL, decorators, and pytest parametrize come up constantly—have a crisp answer ready."
— Surya Singh, Senior Software Engineer & Technical Interviewer with 8+ years in Python and backend architecture
Common interview mistakes to avoid
- Claiming you know generators without explaining memory O(1) vs list O(n)—or when you need multiple passes.
- Implementing a decorator without
functools.wraps—interviewers will notice missing metadata. - Saying "threading doesn't work because of GIL" without clarifying I/O releases the GIL—show you understand when threads help.
- Using
listfor a queue withpop(0)—mention deque for O(1) queue operations. - Ignoring pytest—fixtures, parametrize, and mocking are standard. Know the basics.
- Recommending Django or FastAPI for everything—demonstrate the decision framework.
- Processing large data with pandas without chunking or dtype optimization—memory will bite.
- Skipping the "Result" with metrics in STAR answers—interviewers want numbers.
Frequently asked questions
What Python topics are tested in senior interviews (4+ years)?
Generators and iterators for memory-efficient data processing; decorators for caching, retry, auth, and logging; GIL and concurrency (threading vs multiprocessing vs asyncio); data structures (list, tuple, set, dict, deque, defaultdict, Counter); OOP (abstract classes, mixins, dataclasses, __slots__); error handling and context managers; pytest (fixtures, parametrize, mocking); Django vs FastAPI trade-offs; pandas/numpy and memory profiling; and packaging (venv, Poetry, Docker, CI/CD).
How do I explain generators vs lists in an interview?
Lists materialize all elements in memory—a list of 10 million items consumes 10M * object overhead. Generators yield one item at a time and pause; they are lazy and memory O(1). Use generators for streaming, large files, infinite sequences, or pipelines. Trade-off: you can iterate only once; lists support random access and multiple passes. Bring a real example: "We processed a 2GB log file with a generator; peak memory stayed under 50MB vs 1.2GB with a list."
When do I use threading vs multiprocessing vs asyncio?
Threading: I/O-bound work (network, file, DB)—GIL released during I/O. Multiprocessing: CPU-bound work (heavy computation)—separate processes, no GIL. Asyncio: many concurrent I/O operations—single-threaded, cooperative scheduling, best for 1000+ concurrent connections. Rule: I/O-bound use threading or asyncio; CPU-bound use multiprocessing. Mix carefully: asyncio + threading for blocking libs in thread pool; multiprocessing for parallel CPU.
How important are decorators in Python interviews?
Very. Interviewers expect you to implement or explain @cache, @retry, @auth, custom logging decorators. Know the mechanics: decorator receives the function, returns a wrapper that may add behaviour before/after or replace the function. Show a real decorator you wrote: "We built @retry(max_attempts=3, backoff=exponential) for flaky third-party API calls—retries dropped from 12% to 2%." Mention functools.wraps to preserve metadata.
What data structures should I know for Python interviews?
list (mutable, O(1) append, O(n) insert); tuple (immutable, hashable when elements are); set (O(1) lookup, no duplicates); dict (O(1) average lookup); collections.deque (O(1) append/pop from both ends, good for queues); defaultdict (auto-initialize missing keys); Counter (frequency counting). Know when to use each: deque for FIFO/LIFO queues; Counter for histograms; tuple for dict keys; set for membership.
How do I explain Django vs FastAPI in an interview?
Django: batteries-included, ORM, admin, auth, migrations—best for monolithic apps, rapid development, teams that want conventions. FastAPI: async-first, Pydantic validation, OpenAPI auto-gen—best for APIs, microservices, high throughput. Trade-offs: Django has more built-in; FastAPI is faster for async I/O. Mention: "We use Django for the main app with admin and auth; FastAPI for high-traffic API gateway—10x higher req/s with same hardware."
What pytest patterns should I demonstrate?
Fixtures (scope, dependency injection), parametrize for data-driven tests, mocking with unittest.mock or pytest-mock, pytest.raises for exceptions. Show: conftest.py for shared fixtures; parametrize for testing multiple inputs; patch or mocker.patch for external dependencies. Mention coverage and CI integration. Example: "We parametrize 12 edge cases for the price calculator; fixtures provide a DB session that rolls back after each test."
How do I discuss Python packaging and deployment?
venv or virtualenv for isolation; Poetry or pip-tools for dependency management and locking; pyproject.toml as modern standard; Docker for consistency; CI/CD for lint (ruff), test (pytest), type-check (mypy), build. Mention: "We use Poetry for local dev and CI; Docker multi-stage builds for slim images; pre-commit for lint/format before push." Show you understand dependency pinning, reproducible builds, and security scanning.
Loading...
Related interview guides
- MERN Stack Interview Questions — MongoDB, Express, React, Node.js
- MEAN Stack Interview Questions — MongoDB, Express, Angular, Node.js
- SQL Interview Questions — Real-World Guide for 4+ Years
- AI/ML Engineer Interview Questions — STAR Format Guide
- System Design Interview Questions — Scalability, Distributed Systems
Surya Singh
Azure Solutions Architect & AI Engineer
Microsoft-certified Azure Solutions Architect with 8+ years in enterprise software, cloud architecture, and AI/ML deployment. I build production AI systems and write about what actually works—based on shipping code, not theory.
- Microsoft Certified: Azure Solutions Architect Expert
- Built 20+ production AI/ML pipelines on Azure
- 8+ years in .NET, C#, and cloud-native architecture