Python Developer interview questions
100 real questions with model answers and explanations for Junior candidates.
See a Python Developer resume example →Practice with flashcards
Spaced repetition · Hunter Pass
Questions
Lists, tuples, and sets serve different purposes based on order, mutability, and uniqueness.
- A list is an ordered, mutable sequence.
- A tuple is ordered and immutable, so it can be a dictionary key when its contents are hashable, unlike a list.
- A set is an unordered collection of unique, hashable elements that provides automatic deduplication and average O(1) membership tests.
Why interviewers ask this: The interviewer expects properties plus practical consequences like dict keys and membership speed, not just definitions.
Mutability determines whether an object can change after it is created and affects how it can be used.
- Lists, dictionaries, and sets are mutable, while integers, floats, strings, tuples, and frozensets are immutable.
- Two variables can refer to the same mutable list, so a change made through one name is visible through the other.
- Immutability makes a value hashable and suitable for use as a dictionary key or set element.
Why interviewers ask this: Understanding shared references and mutation side effects is the root of many junior bugs, so interviewers probe it early.
A Python dictionary is a hash table with fast key-based access.
- It uses a key's hash to locate its value, giving average O(1) lookup, insertion, and deletion.
- Keys must be hashable, such as strings, numbers, or tuples of immutable values; lists and dictionaries cannot be keys.
- Since Python 3.7, dictionaries preserve insertion order, but that behavior should not replace explicit sorting.
Why interviewers ask this: The hashable-key requirement and the O(1) intuition show whether the candidate understands the structure beyond syntax.
Slicing extracts part of a sequence with the sequence[start:stop:step] syntax.
- The start index is inclusive, the stop index is exclusive, and any component can be omitted.
- Negative indices count from the end, so items[-3:] gets the last three elements and items[::-1] reverses the sequence.
- Slicing a list creates a new list, which makes items[:] a quick shallow copy.
Why interviewers ask this: Fluency with the exclusive stop and negative indices is a fast signal of everyday Python practice.
A list comprehension is best for a simple, readable transformation or filter that produces a list.
- The expression [x * 2 for x in nums if x > 0] transforms and filters values in one line.
- This form is the Pythonic choice while the transform-and-filter logic remains easy to read.
- A regular loop is clearer when the logic needs multiple statements, side effects, or deep nesting.
Why interviewers ask this: The interviewer checks both idiomatic style and the judgment to abandon it when readability suffers.
Python supports dictionary and set comprehensions as well as lazy generator expressions.
- A dictionary comprehension can look like {u.id: u.name for u in users}, and a set comprehension like {x % 10 for x in nums}.
- A generator expression, such as sum(x * x for x in nums), produces values lazily without building an intermediate list.
- The choice depends mainly on whether the complete result must exist in memory at once.
Why interviewers ask this: Knowing generator expressions exist and why they save memory separates practical users from tutorial readers.
The *args and **kwargs syntax lets functions receive or forward a flexible set of arguments.
- *args collects additional positional arguments into a tuple.
- **kwargs collects additional keyword arguments into a dictionary.
- In a call, func(*items, **options) unpacks a sequence and a dictionary, which is useful in wrappers and decorators that forward arguments unchanged.
Why interviewers ask this: The forwarding use case shows the candidate has seen these in real code, not only in syntax tables.
A mutable default argument is shared across calls and can preserve unexpected state.
- In def add_item(item, items=[]), the list is created once when the function is defined, not for each call.
- Calls that omit items mutate the same list, so a later call can contain values left by an earlier one.
- Use items=None as the default and create items = [] inside the function when items is None.
Why interviewers ask this: This classic trap tests whether the candidate knows default values are evaluated once at definition time.
Python resolves names through Local, Enclosing, Global, and Built-in scopes in that order.
- Reading a variable from an outer scope works without an extra declaration.
- Assigning to a name inside a function creates a local variable unless global or nonlocal is declared.
- This is why mutating a global list can work while rebinding a global counter without global raises UnboundLocalError.
Why interviewers ask this: The assignment-creates-a-local rule and the UnboundLocalError example are what betray real understanding.
Python uses pass by assignment, meaning a function receives a reference to the same object.
- This model is neither classic pass by value nor classic pass by reference.
- Mutating a passed list inside the function changes the caller's list because both refer to the same object.
- Rebinding the parameter to a new object affects only the local name and leaves the caller unchanged.
Why interviewers ask this: This tests the object-reference model, which is the foundation for reasoning about side effects.
The operators == and is compare value equality and object identity, respectively.
- The == operator calls __eq__ to compare values.
- The is operator checks whether two names point to exactly the same object, so two equal lists can satisfy == but not is.
- Identity comparison is idiomatic for singletons, especially x is None, because only one None object exists.
Why interviewers ask this: The x is None convention is the practical detail interviewers listen for beyond the definition.
Shallow and deep copies differ in whether nested objects remain shared with the original.
- A shallow copy creates a new outer container but keeps references to the same inner objects.
- list(data) and data[:] therefore still share nested lists, so changing a nested dictionary can also change the original.
- copy.deepcopy recursively clones the contents and produces a fully independent structure.
Why interviewers ask this: The nested-structure bug is what demonstrates the candidate has actually been bitten by this.
F-strings are the preferred general-purpose string formatting syntax because they are direct, readable, and fast.
- They embed expressions directly, as in f'{user.name} has {count} items', and support format specifications such as f'{price:.2f}'.
- Since Python 3.8, f'{value=}' prints both the expression and its value for quick debugging.
- Percent formatting and str.format still appear in legacy code, while logging deliberately uses lazy percent formatting.
Why interviewers ask this: Format specs and the debugging = form show fluency beyond the basic syntax.
Repeated string concatenation with + inside a large loop is inefficient because strings are immutable.
- Every += creates a new string and copies all previous content, which can make the loop quadratic on large inputs.
- The idiomatic alternative is to collect parts in a list and call ''.join(parts) once.
- For only a few concatenations the difference is negligible, so this concern mainly applies to loops over many items.
Why interviewers ask this: This checks whether the candidate connects immutability to a real performance consequence.
The try, except, else, and finally blocks separate protected code, error handling, successful continuation, and cleanup.
- Code in try runs first, and a matching except block handles an exception.
- The else block runs only when try completes without an exception, keeping the successful path separate from protected code.
- The finally block always runs and is suitable for cleanup such as closing resources not managed by with.
Why interviewers ask this: Knowing what else is for distinguishes people who have read beyond the minimal try/except pattern.
A bare except is dangerous because it can hide genuine bugs and control-flow exceptions.
- It catches KeyboardInterrupt, SystemExit, and mistakes such as NameError, allowing the program to continue in a broken state.
- Code should catch the most specific exception it can handle, such as FileNotFoundError or ValueError.
- A necessary top-level broad handler should catch Exception, log the full traceback, and then re-raise or fail visibly.
Why interviewers ask this: The interviewer checks the instinct to keep failures loud and specific instead of silencing them.
Exceptions should report invalid input or an unrecoverable state as close to the cause as possible.
- A function can reject input explicitly, for example with raise ValueError('amount must be positive').
- A custom Exception subclass such as PaymentDeclinedError lets callers catch failures specific to that code without catching unrelated ValueErrors.
- Raising early with a clear message is safer than returning None and allowing a failure far from its cause.
Why interviewers ask this: Raising early with specific types shows the candidate designs error paths instead of patching them afterwards.
The iterator protocol gives Python a uniform way to traverse lists, files, generators, dictionaries, and other iterable objects.
- An iterable returns an iterator when iter() is called.
- An iterator implements __next__ and produces values until it raises StopIteration.
- A for loop calls iter() once, repeatedly calls next(), and stops when it receives StopIteration.
Why interviewers ask this: Explaining what a for loop desugars to proves the concept is understood, not memorized.
A generator produces values one at a time, making it suitable for large or infinite sequences.
- A generator function uses yield and suspends its execution between produced values.
- Processing a large log file line by line uses constant memory, whereas returning a list would load the full result.
- A generator can be consumed only once and does not provide len().
Why interviewers ask this: The memory argument plus the single-pass limitation is the complete junior-level picture interviewers want.
range() returns a lazy sequence object rather than a prebuilt list.
- It computes values on demand, so even range(10**9) uses almost no memory.
- A range supports len(), indexing, and fast integer membership tests.
- Use list(range(n)) only when an actual list is required; loops benefit from the lazy range object directly.
Why interviewers ask this: A small question that quickly reveals whether the candidate thinks about laziness and memory.
Locked questions
- 21
What do enumerate() and zip() do, and why are they preferred over index arithmetic?
indexes - 22
Which values are falsy in Python, and how does that affect if statements?
python - 23
What is None, and how do you check for it correctly?
- 24
How do you read and write text files in Python?
python - 25
What is a context manager, and what problem does the with statement solve?
context-managers - 26
What is the difference between sorted() and list.sort(), and how does the key parameter work?
sorting - 27
What is a lambda, and when is it appropriate?
lambda - 28
Do you use map() and filter(), or comprehensions?
comprehensions - 29
What can you do with unpacking in Python?
python - 30
How does Python handle memory management and garbage collection?
gcmemorypython - 31
What are decorators, and how do you use them?
decorators - 32
How do you safely read a key that may be missing from a dict?
- 33
What is the difference between list.remove(), list.pop(), and del for removing elements?
- 34
What happens when you create an instance of a class, and what is self?
- 35
What is the difference between instance attributes and class attributes?
- 36
How does inheritance work in Python, and what does super() do?
ooppythonownership - 37
What is the difference between __str__ and __repr__?
dunder - 38
What do you need to implement so that two objects of your class compare equal by value?
- 39
What does the @property decorator do?
decoratorsproperties - 40
What is the difference between @staticmethod and @classmethod?
oop - 41
When do you create a class instead of writing plain functions?
- 42
What are modules and packages, and what happens on import?
- 43
What does if __name__ == '__main__' do, and why use it?
modules - 44
How do you manage project dependencies with pip?
dependenciespip - 45
What is a virtual environment, and why does every project need one?
venv - 46
Which tools from the collections module do you find most useful?
collections - 47
How do you work with dates and times in Python?
python - 48
How do you work with file paths portably?
- 49
How do you serialize and parse JSON in Python?
serializationpython - 50
What are type hints, and does Python enforce them?
pythontyping - 51
Why write automated tests, and what would you test first in a small project?
testing - 52
How does pytest discover and run tests?
pytest - 53
How do you structure a single test so it stays readable?
- 54
What are pytest fixtures for?
pytestfixtures - 55
How do you run the same test against many inputs in pytest?
pytest - 56
When and why do you mock in tests?
mocking - 57
How does pytest differ from the standard unittest module?
pytestunittest - 58
How do you debug a misbehaving Python script beyond adding prints?
python - 59
How do you read a Python traceback?
python - 60
What is the difference between TypeError and ValueError, and when do KeyError and IndexError appear?
indexes - 61
You have been stuck on a bug for two hours. What is your process?
problem-solvingconcurrency - 62
Why use the logging module instead of print in real code?
logging - 63
Describe your basic git workflow when working on a task.
git - 64
Why do teams work through branches and pull requests instead of committing straight to main?
code-review - 65
What is the difference between git fetch and git pull, and what do you do about merge conflicts?
git - 66
What belongs in .gitignore for a Python project?
gitpython - 67
How do you run a query against a database from Python?
databasequeriespython - 68
What is SQL injection, and how do you prevent it in Python?
sqlinjectionpython - 69
What is an ORM, and what are its pros and cons at your level?
orm - 70
A task requires the total number of orders per user from a SQL database. How do you approach it?
sqldatabase - 71
What is a database transaction, and when do you need one in application code?
databasetransactions - 72
What are the main HTTP methods and status code classes you deal with?
httpstatus-codes - 73
How do you call an HTTP API from Python with the requests library?
httppython - 74
An API returns a nested JSON response. How do you extract data from it safely?
api - 75
How do you handle configuration and secrets like API keys in a Python project?
soft-skillsapisecrets - 76
How do you process a CSV file in Python?
concurrencypython - 77
How would you count the most frequent words in a text file?
- 78
How do you process a file that is larger than your RAM?
concurrency - 79
A script crashes with UnicodeDecodeError when reading a file. What is going on, and what do you do?
- 80
How do you add command-line arguments to a Python script?
python - 81
How should a command-line script behave when something goes wrong?
- 82
An external API your script calls fails intermittently. How do you make the script resilient?
api - 83
What does it mean that Python is an interpreted language?
python - 84
What is the GIL, in simple terms, and what does it mean for your code?
gil - 85
What is PEP 8, and how strictly do you follow it?
style - 86
What do you pay attention to when your code is reviewed, and when you read others' code?
- 87
What is a route or endpoint in web frameworks like Flask or FastAPI?
frameworksendpoints - 88
How would you choose between Django, Flask, and FastAPI for a new project?
frameworks - 89
pip install succeeded, but your script fails with ModuleNotFoundError. What do you check?
pippackaging - 90
How do you structure a small Python project?
python - 91
How do you document a function properly?
- 92
What signals tell you a function needs refactoring, and how do you do it safely?
refactoring - 93
Your script runs too slowly. What do you do first?
- 94
You need to pull the timestamp and error message out of each line of a log file. How do you approach it?
- 95
You get a ticket that just says: the export is broken, fix it. What do you do?
- 96
How do you balance figuring things out yourself with asking for help?
- 97
Your merged change broke something in production. What do you do?
- 98
How do you keep improving as a junior Python developer?
python - 99
A senior asks for changes in review that you disagree with. How do you handle it?
soft-skillsconflict - 100
A task is taking much longer than you estimated. When and how do you communicate that?
communicationestimation