Python Interview Questions
Python is one of the most-tested languages in technical interviews, from freshers to senior roles. These are the questions that come up again and again, grouped by theme and tagged by experience level.
102 questions with concise, interview-ready answers.
Python Basics
1. What are the key features of Python? Fresher
Python is a high-level, interpreted, dynamically typed language with automatic memory management. It emphasises readability through significant indentation, supports multiple paradigms (procedural, object-oriented, functional), and ships with a large standard library. It is portable across platforms and has an unusually deep third-party ecosystem.
2. Is Python interpreted or compiled? Fresher
Both, in practice. CPython compiles your source to bytecode (.pyc files) and then the virtual machine interprets that bytecode. So there is a compilation step, but it targets a VM rather than native machine code, and it happens transparently at import time.
3. What is the difference between "is" and "=="? Fresher
== compares values for equality by calling __eq__. "is" compares identity — whether two names refer to the same object in memory. Use == for value comparison; "is" is correct only for singletons like None, True and False. Small ints and short strings are cached by CPython, which is why "is" sometimes appears to work and then fails on larger values.
4. What are Python's mutable and immutable types? Fresher
Immutable types include int, float, str, tuple, bool, bytes and frozenset — once created, their value cannot change. Mutable types include list, dict, set and most custom objects. Mutability determines whether a value can be a dict key (keys must be hashable, which generally means immutable) and whether passing it to a function can affect the caller.
5. What is the difference between a list and a tuple? Fresher
Lists are mutable, use square brackets, and support methods like append and remove. Tuples are immutable, use parentheses, and are hashable if their contents are — so they can be dictionary keys. Tuples are slightly faster and communicate intent: this collection is fixed.
6. What is the difference between a list and a set? Fresher
A list is ordered and allows duplicates, with O(n) membership testing. A set is unordered, stores only unique hashable elements, and gives O(1) membership testing. Reach for a set when you are asking "is this in here?" repeatedly, or when you need union, intersection and difference.
7. What is slicing? Fresher
Slicing extracts a subsequence with sequence[start:stop:step], where stop is exclusive. Negative indices count from the end, and a negative step reverses — s[::-1] is the idiomatic string reverse. Slicing a list returns a new shallow copy; slicing a string returns a new string.
8. What is the difference between a shallow copy and a deep copy? Fresher
A shallow copy (copy.copy, list(), or a full slice) creates a new outer object but shares references to the nested objects, so mutating a nested list is visible through both. A deep copy (copy.deepcopy) recursively duplicates everything, giving a fully independent structure at the cost of more time and memory.
9. What are *args and **kwargs? Fresher
*args collects any extra positional arguments into a tuple; **kwargs collects extra keyword arguments into a dict. They let a function accept a variable number of arguments and are how wrapper and decorator functions forward whatever they receive. The names are convention — the * and ** are what matter.
10. What is a lambda function? Fresher
A lambda is a small anonymous function limited to a single expression, whose value is returned implicitly. It is useful as a short throwaway callable — a sort key, a filter predicate. Anything needing statements, a docstring, or a name in a traceback should be a def instead.
11. What does the "in" operator do on different types? Fresher
On a list or tuple it scans linearly, O(n). On a set or dict it hashes the value, O(1) average. On a string it performs a substring search. The performance difference is why converting a list to a set before repeated membership tests is such a common optimisation.
12. What is the difference between a module and a package? 2–5 yrs
A module is a single .py file. A package is a directory of modules; historically it required an __init__.py, though namespace packages since Python 3.3 do not. Packages let you organise a large codebase into a hierarchy and control what a plain import exposes.
13. What does if __name__ == "__main__" do? 2–5 yrs
When a file runs as a script, Python sets its __name__ to "__main__"; when it is imported, __name__ is the module name. The guard therefore runs the block only on direct execution, so importing the module for its functions does not trigger its script behaviour. It also matters for multiprocessing on Windows, which re-imports the main module.
14. What is the difference between Python 2 and Python 3? 2–5 yrs
Python 3 made print a function, made strings Unicode by default with a separate bytes type, changed integer division to return a float, and turned range and zip into lazy iterators. Python 2 reached end of life in January 2020 and should not be used for new work.
15. What are f-strings and why prefer them? 2–5 yrs
f-strings embed expressions directly in a literal: f"{user.name} has {count} items". They are faster than %-formatting and str.format because they compile to direct concatenation, and they are easier to read because the expression sits where the value appears. Since 3.8 the = specifier also makes debugging output trivial: f"{count=}".
Data Structures
16. What are list comprehensions? Fresher
A concise syntax for building a list from an iterable: [x * 2 for x in items if x > 0]. They are usually faster than an equivalent append loop because the iteration happens in C, and they read as a single expression. Dict and set comprehensions use the same shape with braces.
17. How does a Python dict work internally? Fresher
A dict is a hash table. Keys must be hashable, meaning they implement __hash__ and are typically immutable. Lookups hash the key to find a slot, resolving collisions by open addressing with probing. Since Python 3.7 dicts preserve insertion order as a language guarantee, and the compact layout introduced in 3.6 also made them noticeably smaller.
18. What is a set and when should you use one? Fresher
An unordered collection of unique hashable elements, backed by a hash table. Use it for deduplication, fast membership testing, and set algebra — union (|), intersection (&), difference (-), symmetric difference (^). frozenset is the immutable version, so it can be a dict key or a member of another set.
19. What is the difference between sort() and sorted()? 2–5 yrs
list.sort() sorts in place and returns None — assigning its result is a common bug. sorted() takes any iterable and returns a new list, leaving the original untouched. Both accept key and reverse, and both are stable, meaning equal elements keep their relative order.
20. What does collections.defaultdict do? 2–5 yrs
It is a dict that calls a factory function to supply a value for a missing key instead of raising KeyError. defaultdict(list) lets you append to d[key] without initialising it first. Note that merely reading a missing key inserts it, which surprises people — use .get() if you want a read that does not mutate.
21. What is collections.Counter used for? 2–5 yrs
A dict subclass for counting hashable items. Counter(iterable) tallies occurrences, most_common(n) returns the top n as (item, count) pairs, and Counters support arithmetic. It replaces the manual "if key in d: d[key] += 1" pattern and is the expected answer to word-frequency questions.
22. What is a deque and when is it better than a list? 2–5 yrs
collections.deque is a double-ended queue with O(1) appends and pops at both ends, where a list pays O(n) to pop or insert at the front because everything shifts. Use it for queues, sliding windows, and BFS. It also supports a maxlen that discards from the opposite end automatically.
23. What is a namedtuple, and how does it compare to a dataclass? 2–5 yrs
namedtuple creates an immutable tuple subclass with named fields, so it is lightweight and indexable. A dataclass generates __init__, __repr__ and __eq__ for a normal (by default mutable) class and supports defaults, type hints and methods more naturally. Use namedtuple for lightweight immutable records, dataclass for most structured data.
24. Why can a list not be a dictionary key? Senior
Dict keys must be hashable, and hashability requires the hash to stay constant for the object lifetime. Lists are mutable, so their contents — and any content-based hash — could change while the object sits in a bucket, making the entry unreachable. Python therefore refuses to define __hash__ on list. Use a tuple instead.
25. What is the time complexity of common Python operations? Senior
list: index O(1), append amortised O(1), insert/pop at front O(n), membership O(n). dict and set: insert, lookup and delete O(1) average, O(n) worst case under pathological collisions. Sorting is O(n log n) via Timsort. Knowing that list membership is linear is the single most useful item here.
Functions & Functional Python
26. What is a decorator in Python? Fresher
A decorator is a function that takes another function and returns a replacement, letting you add behaviour without editing the original. The @ syntax is sugar for f = decorator(f). They are used for logging, timing, caching, authentication and retries. Use functools.wraps inside so the wrapped function keeps its name and docstring.
27. What are generators and why use them? Fresher
Generators are functions that use yield to produce values lazily, one at a time, keeping their state between calls. They let you iterate over data that is huge or infinite without holding it all in memory, which is why reading a large file line by line is a generator pattern. A generator expression is the same idea in comprehension syntax with parentheses.
28. What is the difference between a generator and an iterator? Fresher
An iterator is any object implementing __iter__ and __next__. A generator is a convenient way to create one — the yield keyword makes Python build the iterator protocol for you, including state management. Every generator is an iterator; not every iterator is a generator.
29. What is a closure? Fresher
A function that captures and remembers variables from its enclosing scope even after that scope has returned. It is what makes decorators and callback factories work. Use nonlocal if the inner function needs to rebind a captured variable rather than just read it.
30. What is the mutable default argument trap? 2–5 yrs
Default arguments are evaluated once, at function definition time, so def f(items=[]) shares one list across every call and accumulates state. The fix is def f(items=None) followed by "if items is None: items = []". This is one of the most reliably asked Python gotchas.
31. What is functools.lru_cache? 2–5 yrs
A decorator that memoises a function, storing results keyed by the arguments and evicting least-recently-used entries past maxsize. It turns naive recursive solutions into fast ones and is the idiomatic answer to a memoisation question. Arguments must be hashable. functools.cache is the unbounded variant added in 3.9.
32. What do map, filter and reduce do? 2–5 yrs
map applies a function to each item, filter keeps items where a predicate is true, and reduce (in functools) folds a sequence into one value. In practice comprehensions are preferred for map and filter because they read better; reduce survives for genuine accumulations, though an explicit loop is often clearer.
33. What is the difference between yield and return? 2–5 yrs
return exits the function and hands back a value, discarding local state. yield produces a value and suspends the function, preserving locals so execution resumes on the next call. A function containing yield returns a generator when called — its body does not run at all until you iterate it.
34. What are Python scoping rules? Senior
Name lookup follows LEGB: Local, Enclosing, Global, Built-in. Assigning to a name inside a function makes it local for that entire function, which is why reading it before assignment raises UnboundLocalError. Use global to rebind a module-level name and nonlocal to rebind one in an enclosing function.
35. What is a context manager and how do you write one? Senior
An object defining __enter__ and __exit__, used with the with statement so setup and teardown happen reliably even on exception. Files, locks and database connections all use it. The concise way to write one is contextlib.contextmanager on a generator that yields once, with the teardown after the yield in a finally.
OOP in Python
36. What does the "self" parameter do? Fresher
self is the conventional name for the instance a method is called on; Python passes it automatically, so the method signature declares it explicitly. It is how a method reads and writes that particular object's attributes. The name is convention, not syntax, but breaking it will get you comments in code review.
37. What is the difference between @staticmethod and @classmethod? Fresher
A staticmethod receives neither the instance nor the class — it is a plain function namespaced inside the class. A classmethod receives the class as its first argument (cls), which makes it the natural way to write alternative constructors that work correctly under inheritance. Use staticmethod when the method needs neither.
38. What is __init__? Fresher
The initialiser, called after the object is created to set up its state. It is not the constructor in the strict sense — __new__ actually allocates the instance, and __init__ configures it. You rarely override __new__ outside of immutable types and metaclass work.
39. What are dunder methods? Fresher
Double-underscore special methods that hook into language syntax: __len__ backs len(), __eq__ backs ==, __getitem__ backs indexing, __str__ and __repr__ back printing, __enter__/__exit__ back with. Implementing them is how you make your own classes behave like built-in types.
40. How does Python implement private attributes? 2–5 yrs
It does not enforce privacy. A single leading underscore is a convention meaning "internal, do not rely on this". A double leading underscore triggers name mangling to _ClassName__attr, which prevents accidental collisions in subclasses rather than providing real protection. Everything remains reachable.
41. What is the MRO (method resolution order)? 2–5 yrs
The order in which Python searches base classes for an attribute, computed by the C3 linearisation algorithm and visible via ClassName.__mro__. It makes multiple inheritance deterministic and guarantees a class appears before its parents. super() follows the MRO rather than jumping straight to the immediate parent, which is why cooperative multiple inheritance works.
42. What does super() actually do? 2–5 yrs
It returns a proxy that dispatches to the next class in the MRO, not necessarily the direct parent. In single inheritance that distinction is invisible; in multiple inheritance it is what lets each class in the chain run exactly once. Calling the parent explicitly by name breaks that and can execute a class twice.
43. What is the difference between __str__ and __repr__? 2–5 yrs
__str__ is the readable form shown by print() and str(), aimed at end users. __repr__ is the unambiguous form shown in the REPL and in containers, aimed at developers, and ideally looks like valid Python that would recreate the object. If you only implement one, implement __repr__ — str falls back to it.
44. What are __slots__ and when are they worth it? Senior
__slots__ declares a fixed set of attributes, so instances use a compact array instead of a per-instance __dict__. That cuts memory noticeably and speeds attribute access slightly, which matters when you create millions of small objects. The cost is losing dynamic attributes and complicating multiple inheritance.
45. What is a metaclass? Senior
The class of a class — it controls how classes themselves are created, with type being the default. Overriding __new__ or __init__ on a metaclass lets you validate, register or transform classes at definition time, which is how ORMs map model classes to tables. Almost all real cases are better served by __init_subclass__ or a class decorator.
46. What is a property, and why use one instead of a getter? Senior
The @property decorator makes a method accessible like an attribute, with optional @x.setter and @x.deleter. It lets you start with a plain public attribute and later add validation or computation without changing any calling code — which is exactly why Python codebases do not write Java-style getters up front.
47. What is duck typing? Senior
Behaviour is determined by the methods an object actually has, not by its declared type — "if it walks like a duck". Code accepts anything supporting the operations it uses, which is why Python favours try/except (EAFP) over type checks. typing.Protocol expresses this statically without requiring inheritance.
Concurrency & Async
48. What is the GIL (Global Interpreter Lock)? Fresher
The GIL is a mutex in CPython that lets only one thread execute Python bytecode at a time, which is why threads do not give you CPU parallelism. It is released during I/O and inside many C extensions, so threading still helps I/O-bound work. For CPU-bound parallelism use multiprocessing, or a library that drops the GIL such as NumPy.
49. When should you use threading vs multiprocessing vs asyncio? 2–5 yrs
threading for I/O-bound work with blocking libraries. multiprocessing for CPU-bound work, since separate processes have separate GILs. asyncio for very high-concurrency I/O where you can use async-aware libraries, because thousands of coroutines are far cheaper than thousands of threads. The wrong choice usually shows up as code that is concurrent but not faster.
50. What is the difference between concurrency and parallelism? 2–5 yrs
Concurrency is structuring a program so multiple tasks can be in progress and interleave; parallelism is literally executing them at the same instant on multiple cores. Python threads give concurrency but not CPU parallelism because of the GIL. Multiprocessing gives both.
51. What are async and await? 2–5 yrs
async def declares a coroutine, and await suspends it while an awaitable completes, handing control back to the event loop so other coroutines can run. It is cooperative — a coroutine that never awaits blocks everything. Calling a blocking library inside async code is the most common way people get async that is slower than sync.
52. What is the event loop? Senior
The scheduler at the centre of asyncio. It keeps a queue of ready tasks, runs one until it awaits, then switches to the next, watching file descriptors and timers to decide when suspended tasks become ready again. Everything is single-threaded, which is why blocking calls must be pushed to an executor.
53. How do you run blocking code inside an async application? Senior
Hand it to a thread or process pool via loop.run_in_executor, or asyncio.to_thread in 3.9+. That keeps the event loop free while the blocking call occupies a worker thread. Calling requests or a synchronous database driver directly inside a coroutine stalls every other task on that loop.
54. What is the difference between asyncio.gather and asyncio.as_completed? Senior
gather schedules awaitables concurrently and returns all results together in input order, failing fast unless you pass return_exceptions=True. as_completed yields each awaitable as it finishes, so you can start processing the first result without waiting for the slowest. Use gather when you need everything, as_completed when latency to first result matters.
Errors & Testing
55. How does exception handling work in Python? Fresher
try runs code, except catches specific exception types, else runs if no exception occurred, and finally always runs for cleanup. Catch the narrowest exception you can handle; a bare except also swallows KeyboardInterrupt and SystemExit, which is why it is discouraged.
56. What is the difference between an error and an exception? Fresher
In Python both are exceptions — everything raisable derives from BaseException. Syntax errors are raised at compile time and cannot be caught by the code containing them. The distinction interviewers usually want is between exceptions you can reasonably recover from and programming bugs you should let surface.
57. What is EAFP versus LBYL? 2–5 yrs
EAFP — "easier to ask forgiveness than permission" — means attempting the operation and catching the exception, which is the Pythonic default. LBYL — "look before you leap" — checks preconditions first and is prone to race conditions between the check and the use. try/except on a dict access is usually preferred over an "in" check followed by a lookup.
58. How do you write a custom exception? 2–5 yrs
Subclass Exception (not BaseException) and give it a clear name ending in Error. Add attributes if callers need structured detail. Define a single base exception for your package so callers can catch everything from your library with one except clause.
59. What is the difference between unittest and pytest? 2–5 yrs
unittest is in the standard library and follows the xUnit class-based style with assertion methods like assertEqual. pytest uses plain functions and the bare assert statement, rewriting assertions to give detailed failure output, and has a powerful fixture system. pytest can run unittest tests, which is why most projects use it.
60. What is mocking and when do you use it? Senior
Replacing a real dependency with a controllable stand-in so a test stays fast, deterministic and isolated — typically network calls, clocks, filesystems and paid APIs. unittest.mock provides Mock, MagicMock and patch. Over-mocking is the common failure: a test that mocks everything verifies your mocks rather than your code.
Performance & Internals
61. How is memory managed in Python? 2–5 yrs
CPython uses reference counting to free objects as soon as their count hits zero, plus a generational cycle collector to reclaim groups of objects that reference each other. Small objects come from internal pools rather than direct malloc. You never free explicitly, but you can still leak by keeping references alive in caches, globals or closures.
62. What is the difference between range and a list in Python 3? 2–5 yrs
range is a lazy sequence that computes values on demand and stores only start, stop and step, so range(10**9) costs almost nothing. A list materialises every element. range still supports indexing, slicing and membership testing, and its membership test on integers is O(1) arithmetic rather than a scan.
63. Why is string concatenation in a loop slow? 2–5 yrs
Strings are immutable, so each += allocates a new string and copies both operands, giving O(n²) behaviour overall. Collect the pieces in a list and "".join(parts) at the end, which allocates once. CPython has an optimisation that sometimes mutates in place, but it is fragile and not something to rely on.
64. How would you profile a slow Python program? Senior
Start with cProfile to find which functions dominate cumulative time, then line_profiler to narrow to specific lines, and memory_profiler or tracemalloc if the problem is allocation. Measure before optimising — the bottleneck is very often I/O, an accidental O(n²) membership test, or repeated work that belongs in a cache.
65. What are __init__.py and namespace packages? Senior
__init__.py marks a directory as a regular package and runs on import, which is where you control the public API. Since Python 3.3, a directory without it can still be imported as a namespace package, allowing one logical package to span multiple directories. Explicit __init__.py remains the clearer default for application code.
66. What are type hints, and are they enforced at runtime? Senior
Annotations describing expected types: def f(x: int) -> str. They are not enforced — Python ignores them at runtime — and exist for static checkers like mypy, editors, and readers. Pydantic and FastAPI are the notable exception, deliberately reading annotations to validate data at runtime.
67. What is a virtual environment and why does it matter? Senior
An isolated directory with its own interpreter and site-packages, so each project pins its own dependency versions without conflicting with others or the system Python. Created with python -m venv, or managed by tools like poetry and uv. Installing project dependencies globally is how you end up with unreproducible environments.
68. What is the difference between deepcopy and pickle for duplicating objects? Senior
deepcopy walks the object graph in memory and rebuilds it, handling cycles via a memo dict. pickle serialises to a byte stream that can cross process or storage boundaries, then deserialises. pickle is therefore more capable but slower, cannot handle everything (open files, sockets, lambdas), and is unsafe on untrusted input because unpickling can execute arbitrary code.
Iterators, Comprehensions & Idioms
69. What is the iterator protocol? Fresher
An iterable implements __iter__ returning an iterator; the iterator implements __next__ returning the next value and raising StopIteration when exhausted. for loops are sugar over this. Because an iterator is consumed once, iterating it a second time yields nothing — which is why a generator you have already looped over appears empty.
70. What does enumerate() do and why prefer it? Fresher
It yields (index, value) pairs, so you get the counter without maintaining one manually. It accepts a start argument, so enumerate(items, 1) numbers from one. Writing "for i in range(len(items))" and indexing is the pattern it replaces, and reviewers will flag it.
71. What does zip() do, and what happens with unequal lengths? Fresher
It pairs elements from multiple iterables into tuples, stopping at the shortest — silently, which can hide bugs. Pass strict=True (Python 3.10+) to raise on a length mismatch, or use itertools.zip_longest to pad. zip(*matrix) is also the idiomatic transpose.
72. What is the difference between a list comprehension and a generator expression? Fresher
A list comprehension uses brackets and materialises the whole list immediately. A generator expression uses parentheses and yields lazily, holding only one value at a time. For a one-pass aggregation like sum(x*x for x in nums) the generator avoids building an intermediate list entirely.
73. What is unpacking, and what does the starred form do? 2–5 yrs
Unpacking assigns from an iterable: a, b = pair. A starred target absorbs the remainder as a list — first, *rest = items, or a, *middle, z = items. It also works in function calls, f(*args), and in literals to merge: [*a, *b] and {**d1, **d2}.
74. What do any() and all() do, and what do they return on an empty iterable? 2–5 yrs
any() is True if at least one element is truthy; all() is True if every element is. Both short-circuit. On an empty iterable any() is False and all() is True — the latter surprises people, but it is the mathematically consistent answer for a universally quantified statement over nothing.
75. How do you sort a list of dicts or objects by a field? 2–5 yrs
Pass a key function: sorted(users, key=lambda u: u["age"]), or operator.itemgetter("age") which is faster and clearer. For multiple keys return a tuple: key=lambda u: (u["dept"], -u["salary"]). Sorting is stable, so sorting twice by minor then major key also works.
76. What useful tools does itertools provide? 2–5 yrs
chain flattens multiple iterables, groupby groups consecutive equal items (so sort first), combinations and permutations enumerate selections, product gives the Cartesian product, islice slices lazily, and count/cycle/repeat produce infinite sequences. All are lazy, which is the point on large data.
77. What is the walrus operator? 2–5 yrs
The assignment expression :=, added in 3.8, which assigns and returns a value in one expression. It is useful when you would otherwise compute something twice or restructure a loop — while (line := f.readline()): or [y for x in data if (y := f(x)) > 0]. Overusing it hurts readability.
78. Why should you avoid mutating a list while iterating over it? Senior
The iterator tracks a position index, so removing an element shifts everything left and the loop skips the next item — silently producing wrong results rather than an error. Iterate over a copy (for x in items[:]), build a new list with a comprehension, or use a while loop with explicit index control.
Standard Library & Tooling
79. How do you read and write files safely in Python? Fresher
Use a with statement so the file closes even on exception: with open(path, encoding="utf-8") as f. Always pass encoding explicitly — relying on the platform default is a classic source of works-on-my-machine bugs. Iterating the file object reads line by line without loading it all into memory.
80. What is the difference between os.path and pathlib? Fresher
os.path is the older string-based API; pathlib provides a Path object with operators and methods — path / "sub" / "file.txt", .exists(), .read_text(), .glob(). pathlib is the modern default because it handles separators correctly across platforms and reads far better.
81. How do you work with JSON in Python? Fresher
json.loads/dumps convert between strings and Python objects; json.load/dump work with file objects. dumps takes indent for readability and default for a fallback serialiser on unsupported types like datetime. Note that JSON object keys are always strings, so integer dict keys come back as strings after a round trip.
82. How do you handle dates and times? 2–5 yrs
Use datetime with timezone-aware objects — datetime.now(timezone.utc), not the naive utcnow(), which is deprecated for exactly this reason. Store UTC, convert at the display boundary, and use the standard-library zoneinfo for time zones. Comparing a naive and an aware datetime raises TypeError.
83. What is the difference between print and logging? 2–5 yrs
print writes to stdout with no level, no timestamp, no destination control and no way to disable it without editing code. logging gives levels, per-module loggers, configurable handlers and formatters, and can route to files or aggregators. Any code that will run unattended should use logging.
84. How do you use regular expressions in Python? 2–5 yrs
re.match anchors at the start, re.search scans anywhere, re.findall returns all matches, re.sub substitutes. Use raw strings for patterns so backslashes survive, and re.compile when reusing a pattern in a loop. Named groups, (?P<name>...), make the resulting code readable.
85. What is the difference between dataclasses and Pydantic models? 2–5 yrs
A dataclass generates boilerplate — __init__, __repr__, __eq__ — and ignores type hints at runtime. A Pydantic model reads the annotations and actually validates and coerces input, which is why it underpins FastAPI. Use dataclasses for internal structures, Pydantic at trust boundaries where data arrives from outside.
86. What is the difference between subprocess.run and os.system? Senior
os.system passes a string to the shell and gives you only an exit code, with shell-injection risk if any part is user-controlled. subprocess.run takes an argument list, avoids the shell entirely by default, and returns stdout, stderr and the return code. Use subprocess with a list and shell=False.
87. How would you handle configuration and secrets in a Python application? Senior
Read configuration from environment variables so the same artefact runs in every environment, with a typed settings object (Pydantic Settings or similar) validating at startup so a missing value fails fast. Secrets come from the platform secret store, never from committed files, and .env files are for local development only.
Interview Coding Patterns
88. How do you reverse a string or a list in Python? Fresher
For a string, s[::-1] — slicing with a negative step. For a list, either lst[::-1] for a new reversed list, lst.reverse() to reverse in place, or reversed(lst) for a lazy iterator. Interviewers sometimes ask you to do it manually with two pointers to check you understand the mechanics.
89. How do you check whether a string is a palindrome? Fresher
The concise version is s == s[::-1], usually after normalising case and stripping non-alphanumerics. The version that scores better in an interview is two pointers moving inward, because it is O(1) extra space rather than allocating a reversed copy — say which you are doing and why.
90. How do you count word or character frequency? Fresher
collections.Counter(words) is the expected answer, with .most_common(n) for the top results. Doing it manually with a dict and dict.get(key, 0) + 1 demonstrates the same understanding if the interviewer bans the import.
91. How do you remove duplicates from a list while preserving order? Fresher
list(dict.fromkeys(items)) — dicts preserve insertion order since 3.7, so this is both idiomatic and O(n). set(items) also deduplicates but loses order, which is the trap in the question.
92. How do you find the two numbers in a list that sum to a target? 2–5 yrs
One pass with a dict mapping value to index: for each number, check whether target minus it has already been seen. That is O(n) time and O(n) space, versus the O(n²) nested loop. It is the canonical demonstration that a hash map turns a search into a lookup.
93. How do you merge two dictionaries? 2–5 yrs
In Python 3.9+ use d1 | d2, which returns a new dict with d2 winning on conflicts. Before that, {**d1, **d2}. d1.update(d2) mutates d1 in place instead of returning a new one. For nested merging you have to recurse — none of these deep-merge.
94. How do you flatten a nested list? 2–5 yrs
For one level, [x for sub in nested for x in sub] or itertools.chain.from_iterable(nested). For arbitrary depth you need recursion with an isinstance check, or an explicit stack — say which the question means, because the two answers are quite different.
95. How would you process a file too large to fit in memory? Senior
Stream it. Iterate the file object line by line, or read fixed-size chunks for binary data, and keep only aggregates rather than accumulating rows. If you need grouping, either sort externally first or use a bounded structure like a Counter with eviction. The key point is that peak memory should be independent of file size.
96. How do you check whether two strings are anagrams? Fresher
Compare sorted(a) == sorted(b) — O(n log n) and one line — or compare Counter(a) == Counter(b), which is O(n). Normalise case and strip spaces first if the question implies phrases. Mention the complexity difference; that is usually the point of asking.
97. How do you find the largest or smallest N elements? Fresher
heapq.nlargest(n, items) and nsmallest, which are O(n log k) and better than a full sort when n is small relative to the list. Both accept a key function. Sorting and slicing works too but does more work than the question requires.
98. How do you swap two variables in Python? Fresher
a, b = b, a. The right-hand side is evaluated into a tuple first, so no temporary variable is needed and it works for any number of names. It is a small thing, but it is the kind of idiom interviewers use to gauge whether you write Python or write another language in Python.
99. How do you group a list of records by a key? 2–5 yrs
collections.defaultdict(list) and append in a single pass — O(n) and the idiomatic answer. itertools.groupby also works but only groups *consecutive* equal keys, so you must sort first, which makes it O(n log n) and is a common source of wrong answers.
100. How would you implement a simple retry with backoff? 2–5 yrs
A loop with a bounded attempt count, catching only the exceptions worth retrying, sleeping for an exponentially growing interval plus a small random jitter, and re-raising after the final attempt. Jitter matters — without it, many clients retrying in lockstep produce a synchronised thundering herd.
101. How do you find the first non-repeating character in a string? 2–5 yrs
Build a Counter in one pass, then iterate the string again and return the first character with a count of one. Two passes, O(n) time and O(k) space for the alphabet. Because dicts preserve insertion order, you can also just scan the Counter itself.
102. How would you deduplicate a large stream of IDs with bounded memory? Senior
If exactness is required, you cannot do it in sublinear space — so shard by hash and process each shard separately, or use an on-disk set. If approximate is acceptable, a Bloom filter gives constant memory with a tunable false-positive rate and no false negatives. State which trade-off the question is asking for before writing code.
Get these answered live in your real interview
NostrobeAI is a real-time AI interview copilot — it hears the question and drafts a strong answer on your screen, invisible on Zoom, Meet, and Teams. One-time pricing, no subscription.
Try NostrobeAI free