Absolutely.
Here’s a backend-focused Python interview Q&A set from basics
to advanced, centered around the topics you listed and the kinds of
follow-up questions interviewers usually ask.
I’ll keep the answers in an interview style, so they are easier to say out
loud.
---
# Python interview questions and answers for backend roles
## 1. What are Python’s main built-in data types?
Python has several core built-in data types:
- Numeric: `int`, `float`, `complex`
- Boolean: `bool`
- Sequence: `str`, `list`, `tuple`, `range`
- Set types: `set`, `frozenset`
- Mapping: `dict`
- Binary: `bytes`, `bytearray`, `memoryview`
- Special: `NoneType`
For backend work, the most common ones are `str`, `list`, `tuple`, `dict`,
`set`, `bytes`, `bool`, and `None`.
---
## 2. What is the difference between a list and a tuple?
A `list` is mutable, and a `tuple` is immutable.
```python
a = [1, 2, 3]
a[0] = 10
b = (1, 2, 3)
# b[0] = 10 # error
```
Use a list when data needs to change. Use a tuple when the collection
should stay fixed.
In practice:
- `list` for dynamic collections
- `tuple` for fixed records, return values, or hashable groupings when
contents are immutable
Also, tuples are generally a bit lighter than lists.
---
## 3. When would you prefer a tuple over a list?
I’d prefer a tuple when the data is not meant to change, such as:
- coordinates
- database row-like fixed values
- function return values
- dictionary keys, if the tuple contains only hashable items
It also communicates intent better. If I use a tuple, I’m telling other
developers this value should stay constant.
---
## 4. What is the difference between a set and a dict?
A `set` stores unique values only. A `dict` stores key-value pairs.
```python
s = {1, 2, 3}
d = {"name": "Sam", "role": "backend"}
```
Use a set for:
- uniqueness
- fast membership checks
- removing duplicates
Use a dict for:
- structured lookup by key
- storing related data
- counters, caches, mappings
Both are hash-table based, so membership checks are usually fast.
---
## 5. What’s the difference between mutable and immutable types?
Mutable objects can be changed after creation. Immutable objects cannot.
Mutable:
- `list`
- `dict`
- `set`
- `bytearray`
Immutable:
- `int`
- `float`
- `bool`
- `str`
- `tuple`
- `bytes`
- `frozenset`
Example:
```python
x = [1, 2]
[Link](3) # same object changed
s = "abc"
s = s + "d" # new object created
```
This matters a lot in function arguments, hashing, shared references, and
concurrency-safe thinking.
---
## 6. Why does mutability matter in interviews and real backend code?
Because it affects side effects and bugs.
For example:
- shared mutable state can cause unexpected changes
- mutable default arguments can create hidden bugs
- immutable objects are safer as dictionary keys
- understanding mutability helps reason about object references
In backend systems, avoiding accidental mutation makes code easier to
debug and test.
---
## 7. What is the difference between `str` and `bytes`?
`str` is text, meaning Unicode characters. `bytes` is raw binary data.
```python
text = "hello"
raw = b"hello"
```
Use `str` for human-readable text.
Use `bytes` for:
- network data
- file streams
- encryption
- images
- protocol payloads
You convert between them using encoding and decoding:
```python
b = "hello".encode("utf-8")
s = [Link]("utf-8")
```
In backend work, this matters a lot in APIs, sockets, file handling, and
cryptography.
---
## 8. Why is it important to know `str` vs `bytes` for backend
engineering?
Because many real systems operate on raw bytes, not text.
Examples:
- HTTP body payloads
- signatures and hashes
- reading files
- encryption/decryption
- Kafka or message queue payloads
- socket communication
A common bug is mixing text and bytes incorrectly and getting encoding or
decoding errors.
---
## 9. In Python, is everything really an object?
Yes. In Python, everything is an object, including:
- integers
- strings
- functions
- classes
- modules
That means every object has:
- a type
- an identity
- a value
And objects can be passed around, assigned, stored in data structures, and
inspected at runtime.
---
## 10. What do type, value, and identity mean in Python?
Every Python object has:
- **type**: what kind of object it is
- **value**: the data it represents
- **identity**: the object’s unique identity in memory for its lifetime
Example:
```python
x = [1, 2]
print(type(x)) # <class 'list'>
print(x) # value: [1, 2]
print(id(x)) # identity
```
This is part of Python’s object model and helps explain assignment,
mutation, and comparison behavior.
---
## 11. What is the difference between `is` and `==`?
`==` compares values.
`is` compares identity.
```python
a = [1, 2]
b = [1, 2]
print(a == b) # True
print(a is b) # False
```
Use `==` when you care about equality of content.
Use `is` when you care whether two names point to the same object.
A common correct use is:
```python
if x is None:
...
```
---
## 12. Why should `None` usually be compared with `is` and not `==`?
Because `None` is a singleton. There is only one `None` object.
So the idiomatic and correct check is:
```python
if value is None:
...
```
Using `==` may still work, but `is` expresses identity and avoids weird
behavior if `__eq__` is customized.
---
## 13. What are reference semantics in Python?
Variables in Python store references to objects, not the objects
themselves.
So assignment does not copy the object. It creates another reference to
the same object.
```python
a = [1, 2]
b = a
[Link](3)
print(a) # [1, 2, 3]
```
This is why aliasing happens and why mutation through one name affects the
other.
---
## 14. What is aliasing?
Aliasing means two or more variables refer to the same object.
```python
a = {"x": 1}
b = a
b["y"] = 2
print(a) # {'x': 1, 'y': 2}
```
This is common in Python and important to understand when passing mutable
objects to functions.
---
## 15. How do you avoid accidental aliasing bugs?
Some common ways:
- create copies when needed
- use immutable data where possible
- be careful with nested mutable structures
- avoid shared global mutable state
Examples:
```python
a = [1, 2]
b = [Link]()
```
For nested structures, shallow copy may not be enough, so sometimes
`[Link]()` is needed.
---
## 16. What is a shallow copy vs deep copy?
A shallow copy copies the outer container but not nested objects.
A deep copy recursively copies nested objects too.
```python
import copy
a = [[1, 2], [3, 4]]
b = [Link](a)
c = [Link](a)
```
If you mutate an inner list in `b`, it can affect `a`.
With `deepcopy`, inner objects are copied too.
---
## 17. What does it mean that functions are first-class in Python?
It means functions are treated like any other object. You can:
- assign them to variables
- pass them as arguments
- return them from other functions
- store them in data structures
```python
def greet(name):
return f"Hello {name}"
f = greet
print(f("Sam"))
```
This enables higher-order functions, decorators, callbacks, and flexible
design.
---
## 18. What is a higher-order function?
A higher-order function either:
- takes another function as an argument, or
- returns a function
Example:
```python
def apply_twice(fn, x):
return fn(fn(x))
```
Examples from Python built-ins:
- `map`
- `filter`
- `sorted` with `key`
- decorators
---
## 19. What is a closure?
A closure is a function that remembers variables from its enclosing scope
even after that outer function has finished executing.
```python
def outer(x):
def inner(y):
return x + y
return inner
add_10 = outer(10)
print(add_10(5)) # 15
```
The inner function closes over `x`.
Closures are useful for factories, decorators, and encapsulating state.
---
## 20. What is the mutable default argument pitfall?
Default argument values are evaluated once when the function is defined,
not each time it is called.
So this is dangerous:
```python
def add_item(item, items=[]):
[Link](item)
return items
```
Calling it multiple times keeps reusing the same list.
Correct version:
```python
def add_item(item, items=None):
if items is None:
items = []
[Link](item)
return items
```
This is a very common interview question.
---
## 21. Why does the mutable default argument bug happen?
Because Python evaluates default arguments once at function definition
time and stores that object.
So if the default is mutable and you mutate it, future calls see the
mutated object.
It surprises people because many assume a fresh default is created on
every call, but that is not how Python works.
---
## 22. What is late binding in closures?
Late binding means variables used in closures are looked up when the inner
function is called, not when it is defined.
Example:
```python
funcs = []
for i in range(3):
[Link](lambda: i)
print([f() for f in funcs]) # [2, 2, 2]
```
All lambdas refer to the same final `i`.
Fix it by binding the current value:
```python
funcs = []
for i in range(3):
[Link](lambda i=i: i)
print([f() for f in funcs]) # [0, 1, 2]
```
---
## 23. Explain the LEGB rule.
Python resolves names in this order:
- **L**ocal
- **E**nclosing
- **G**lobal
- **B**uilt-in
Example:
```python
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x)
inner()
```
The closest matching scope is used first.
This is important for closures, nested functions, and debugging name
resolution.
---
## 24. What is the difference between `global` and `nonlocal`?
`global` refers to a module-level variable.
`nonlocal` refers to a variable in the nearest enclosing function scope.
Example:
```python
x = 10
def f():
global x
x = 20
```
```python
def outer():
x = 10
def inner():
nonlocal x
x = 20
```
Use `nonlocal` in closures when you want to update outer function state.
---
## 25. What does `len()` do?
`len()` returns the number of items in a container.
```python
len([1, 2, 3]) # 3
len("hello") # 5
len({"a": 1}) # 1
```
For custom classes, it works via the `__len__` special method.
---
## 26. Why is `enumerate()` better than manually using an index?
`enumerate()` gives both index and value cleanly and avoids manual
indexing bugs.
```python
for idx, value in enumerate(items):
print(idx, value)
```
It is more Pythonic and readable than:
```python
for i in range(len(items)):
print(i, items[i])
```
---
## 27. What does `zip()` do?
`zip()` combines multiple iterables element by element.
```python
names = ["a", "b"]
scores = [10, 20]
for name, score in zip(names, scores):
print(name, score)
```
It is useful for parallel iteration.
In Python 3, `zip()` returns an iterator, not a list.
---
## 28. What is the use of `any()` and `all()`?
`any()` returns `True` if at least one element is truthy.
`all()` returns `True` if all elements are truthy.
```python
any([False, False, True]) # True
all([True, True, False]) # False
```
They are useful in validations, filters, and condition checks.
---
## 29. What is the difference between `sorted()` and `[Link]()`?
`sorted()` returns a new sorted iterable result.
`[Link]()` sorts the list in place.
```python
nums = [3, 1, 2]
a = sorted(nums) # [1, 2, 3]
[Link]() # nums becomes [1, 2, 3]
```
`sorted()` works with any iterable.
`[Link]()` only works on lists.
Both support `key` and `reverse`.
---
## 30. Why is the `key` parameter in `sorted()` important?
It lets you define custom sorting logic.
```python
words = ["aaa", "b", "cc"]
sorted(words, key=len) # ['b', 'cc', 'aaa']
```
In backend work, it’s very useful when sorting objects by timestamps,
priorities, scores, or attributes.
---
## 31. What does `reversed()` do?
`reversed()` returns an iterator that traverses a sequence in reverse
order.
```python
nums = [1, 2, 3]
for x in reversed(nums):
print(x)
```
It does not modify the original sequence.
---
## 32. What is `isinstance()` and why is it preferred over `type(x) ==
...` in many cases?
`isinstance(obj, cls)` checks whether an object is an instance of a class
or its subclasses.
```python
isinstance(True, int) # True
```
It is often preferred because it supports inheritance, while `type(x) ==
cls` checks only exact type equality.
---
## 33. What do `getattr`, `setattr`, and `hasattr` do?
They are built-ins for dynamic attribute access.
```python
class User:
pass
u = User()
setattr(u, "name", "Sam")
print(getattr(u, "name"))
print(hasattr(u, "name"))
```
They are useful in generic frameworks, serializers, ORMs, and dynamic
programming.
---
## 34. What is `range()`?
`range()` represents a sequence of integers, commonly used in loops.
```python
for i in range(5):
print(i)
```
It is memory-efficient because it does not create a full list in Python 3.
---
## 35. What is the difference between `map()` and a list comprehension?
`map()` applies a function to each item in an iterable.
```python
list(map([Link], ["a", "b"]))
```
Equivalent list comprehension:
```python
[[Link]() for x in ["a", "b"]]
```
In Python, list comprehensions are usually more readable unless an
existing function already fits well.
---
## 36. What is the difference between `filter()` and a list comprehension?
`filter()` keeps items where the function returns truthy.
```python
list(filter(lambda x: x > 0, [-1, 0, 1, 2]))
```
Equivalent:
```python
[x for x in [-1, 0, 1, 2] if x > 0]
```
Again, comprehensions are often easier to read.
---
## 37. What is a Python iterator?
An iterator is an object that produces values one at a time and remembers
its state.
It implements:
- `__iter__()`
- `__next__()`
Example:
```python
it = iter([1, 2, 3])
print(next(it))
```
Iterators are important for memory efficiency and streaming large
datasets.
---
## 38. What is an iterable?
An iterable is any object you can loop over.
Examples:
- list
- tuple
- dict
- set
- string
- generator
An iterable can produce an iterator using `iter()`.
---
## 39. What is a generator?
A generator is a simple way to create iterators using `yield`.
```python
def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1
```
Generators are memory-efficient because they yield values lazily instead
of storing everything in memory.
This is very useful in backend systems for large file processing or
streaming data.
---
## 40. What is the difference between a generator and a normal function?
A normal function returns once and exits.
A generator yields multiple values over time and resumes where it left
off.
Using `yield` makes the function a generator.
---
## 41. Why are generators useful in backend systems?
They help when:
- reading large files line by line
- streaming API responses
- processing records lazily
- reducing memory usage
- building pipelines
They are a good fit when you do not want to load all data into memory at
once.
---
## 42. What is list comprehension and why is it useful?
List comprehension is a concise way to create lists.
```python
squares = [x * x for x in range(5)]
```
It is useful because it is often shorter and clearer than manual loops.
But I avoid making it too complex. If readability suffers, I use a normal
loop.
---
## 43. What is the difference between `append()` and `extend()` in a list?
`append()` adds one object as a single element.
`extend()` adds elements from an iterable.
```python
a = [1, 2]
[Link]([3, 4]) # [1, 2, [3, 4]]
b = [1, 2]
[Link]([3, 4]) # [1, 2, 3, 4]
```
---
## 44. Why are dictionaries so important in Python backend code?
Because they are the default structure for:
- JSON-like data
- request/response payloads
- configuration
- caching
- lookup tables
They are flexible and fast for key-based access.
---
## 45. Are dictionaries ordered in Python?
In modern Python, yes. Dictionary insertion order is preserved.
That means iteration happens in insertion order.
This became a language guarantee starting from Python 3.7.
---
## 46. Can dictionary keys be mutable?
No. Keys must be hashable, which generally means immutable.
Valid keys:
- `str`
- `int`
- `tuple` of hashable items
Invalid keys:
- `list`
- `dict`
- `set`
---
## 47. What does hashable mean?
A hashable object has a stable hash value during its lifetime and can be
used as a dictionary key or set element.
Typically immutable objects are hashable.
This matters because dicts and sets rely on hashing internally.
---
## 48. What is duck typing in Python?
Duck typing means Python cares more about behavior than explicit type.
“If it behaves like what I need, I can use it.”
Example: if an object supports iteration, I can iterate over it,
regardless of its exact class.
This makes Python flexible, but in larger backend systems I still balance
that with clear interfaces and type hints.
---
## 49. What are type hints in Python, and why are they useful?
Type hints let you annotate expected types.
```python
def add(a: int, b: int) -> int:
return a + b
```
They improve:
- readability
- editor support
- static analysis
- maintainability
They do not enforce types at runtime by default, but tools like `mypy` can
check them.
For backend systems, they help a lot in larger codebases.
---
## 50. Are type hints enforced at runtime?
No, not by default.
Python will still run this:
```python
def add(a: int, b: int) -> int:
return a + b
```
even if wrong types are passed, unless runtime validation is added.
Type hints are mostly for humans, IDEs, and static type checkers.
---
## 51. What is the difference between `deepcopy` and just assigning one
variable to another?
Assignment only creates another reference to the same object.
`deepcopy` creates a completely independent recursive copy.
This matters when you want full isolation between nested mutable
structures.
---
## 52. What is the difference between `pass`, `continue`, and `break`?
- `pass` does nothing
- `continue` skips to the next loop iteration
- `break` exits the loop completely
```python
for x in range(5):
if x == 1:
continue
if x == 3:
break
```
---
## 53. What is truthiness in Python?
Objects are evaluated as truthy or falsy in boolean contexts.
Falsy examples:
- `None`
- `False`
- `0`
- `0.0`
- `""`
- `[]`
- `{}`
- `set()`
Everything else is generally truthy.
This is useful, but in backend code I try to be explicit when `None` and
empty values have different meanings.
---
## 54. What is the difference between `None`, `False`, and an empty
string?
They are all falsy, but they mean different things.
- `None` means no value / missing
- `False` means boolean false
- `""` means empty text
In backend APIs, confusing these can cause bugs, so I avoid relying only
on truthiness when semantics matter.
---
## 55. What are `*args` and `**kwargs`?
`*args` collects positional arguments into a tuple.
`**kwargs` collects keyword arguments into a dictionary.
```python
def f(*args, **kwargs):
print(args)
print(kwargs)
```
They are useful for wrappers, decorators, extensible APIs, and forwarding
arguments.
---
## 56. What is unpacking in Python?
Unpacking extracts values from iterables or mappings.
```python
a, b = [1, 2]
```
Function call unpacking:
```python
nums = [1, 2, 3]
print(*nums)
```
Dictionary unpacking:
```python
d1 = {"a": 1}
d2 = {"b": 2}
merged = {**d1, **d2}
```
This is commonly used in clean Python code.
---
## 57. What is exception handling in Python?
Python handles errors using `try`, `except`, `else`, and `finally`.
```python
try:
x = 1 / 0
except ZeroDivisionError:
print("cannot divide by zero")
finally:
print("done")
```
In backend code, good exception handling is important for:
- validation
- error mapping
- retries
- logging
- cleanup
---
## 58. What is the difference between `except Exception` and a bare
`except:`?
`except Exception` catches most normal exceptions.
Bare `except:` catches almost everything, including things like
`KeyboardInterrupt` and `SystemExit`.
In production code, bare `except:` is usually too broad and risky.
---
## 59. What is EAFP vs LBYL in Python?
EAFP means “Easier to Ask Forgiveness than Permission”.
LBYL means “Look Before You Leap”.
Python often prefers EAFP.
Example:
```python
try:
value = d["key"]
except KeyError:
value = None
```
instead of:
```python
if "key" in d:
value = d["key"]
else:
value = None
```
EAFP can be cleaner and avoids race conditions in some cases.
---
## 60. What is a decorator?
A decorator is a function that wraps another function to extend behavior
without modifying its code directly.
```python
def log_calls(fn):
def wrapper(*args, **kwargs):
print("calling", fn.__name__)
return fn(*args, **kwargs)
return wrapper
```
Used as:
```python
@log_calls
def hello():
print("hi")
```
Decorators are common in frameworks, auth, logging, retries, and
validation.
---
## 61. What is the difference between `@staticmethod`, `@classmethod`, and
instance methods?
- Instance method: takes `self`
- Class method: takes `cls`
- Static method: takes neither automatically
```python
class A:
def inst(self): ...
@classmethod
def cl(cls): ...
@staticmethod
def st(): ...
```
Use:
- instance method for object-specific behavior
- class method for alternative constructors or class-level logic
- static method for related utility logic
---
## 62. What is the difference between `__str__` and `__repr__`?
`__str__` is user-friendly string representation.
`__repr__` is developer-focused representation.
If `__str__` is not defined, Python falls back to `__repr__`.
For debugging and logs, a good `__repr__` is very useful.
---
## 63. What is a dunder method?
Dunder means “double underscore” method, like:
- `__init__`
- `__len__`
- `__iter__`
- `__repr__`
- `__eq__`
These special methods define how objects behave with Python syntax and
built-ins.
Example: `len(obj)` calls `obj.__len__()`.
---
## 64. What is the difference between `__new__` and `__init__`?
`__new__` creates the object.
`__init__` initializes the object after creation.
Most of the time, we only override `__init__`.
`__new__` is mainly used in advanced cases, especially with immutable
types or metaprogramming.
---
## 65. What is the GIL?
The GIL is the Global Interpreter Lock in CPython. It allows only one
thread to execute Python bytecode at a time.
That means CPU-bound Python threads do not truly run in parallel in one
process.
But threads are still useful for I/O-bound tasks like:
- API calls
- DB queries
- file I/O
For CPU-bound work, multiprocessing is often better.
---
## 66. How does the GIL affect backend applications?
For typical I/O-heavy backend services, threads can still help because
they release the GIL while waiting on I/O.
But for heavy CPU work, Python threads won’t scale well due to the GIL.
So for backend services:
- async or threads for I/O-bound concurrency
- multiprocessing or external workers for CPU-heavy jobs
---
## 67. What is the difference between concurrency and parallelism in
Python?
Concurrency is handling multiple tasks in overlapping time.
Parallelism is actually executing multiple tasks at the same time.
In Python:
- threading helps concurrency, especially for I/O
- multiprocessing helps true parallelism for CPU-bound work
---
## 68. What is `asyncio` and when would you use it?
`asyncio` is Python’s built-in framework for asynchronous I/O using
`async` and `await`.
It is useful for:
- network-heavy services
- many concurrent I/O operations
- HTTP clients/servers
- websockets
Example:
```python
async def fetch():
...
```
I would use it when the service is heavily I/O-bound and benefits from
non-blocking concurrency.
---
## 69. What is the difference between threading, multiprocessing, and
asyncio?
- **threading**: useful for I/O-bound tasks, shared memory, limited by GIL
for CPU
- **multiprocessing**: separate processes, true CPU parallelism, heavier
- **asyncio**: cooperative concurrency for I/O-bound tasks,
single-threaded event loop
Choice depends on workload type.
---
## 70. What is Pythonic code?
Pythonic code is code that follows Python idioms and prioritizes
readability, simplicity, and clarity.
Examples:
- using `enumerate()` instead of manual indexes
- using comprehensions when readable
- using `is None`
- using built-ins effectively
- preferring clear names and simple control flow
For senior roles, writing maintainable code is more important than showing
clever tricks.
---
# Backend-focused advanced follow-up questions
## 71. How would you explain Python’s memory model in simple terms?
Python variables are references to objects. Objects live somewhere in
memory, and names point to them.
Mutating a mutable object changes that same object. Rebinding a variable
points it to a different object.
That’s why assignment is not the same as copying.
---
## 72. Why can tuples sometimes still contain mutable values?
Because tuple immutability only means the tuple structure cannot change.
But an element inside it may itself be mutable.
```python
t = ([1, 2], 3)
t[0].append(4) # valid
```
So the tuple is immutable, but the nested list is not.
---
## 73. Why is understanding object identity useful in debugging?
Because many bugs come from unintended shared references.
If two variables unexpectedly affect each other, checking identity helps
confirm whether they point to the same object.
---
## 74. What are some common Python interview traps?
Some very common ones are:
- mutable default arguments
- `is` vs `==`
- late binding in closures
- shallow copy vs deep copy
- list multiplication with nested mutables
- truthiness confusion with `None` vs empty values
- assuming dict keys can be mutable
- misunderstanding GIL and concurrency
---
## 75. What is wrong with this code?
```python
matrix = [[0] * 3] * 3
matrix[0][0] = 1
```
All rows refer to the same inner list because of reference reuse.
So changing one row changes all rows.
Correct version:
```python
matrix = [[0] * 3 for _ in range(3)]
```
---
## 76. Why are built-ins often preferred over manual loops?
Because built-ins are:
- more readable
- often optimized in C
- less error-prone
- idiomatic Python
Examples:
- `sum(values)` instead of manual addition loop
- `any(...)`, `all(...)`, `sorted(...)`, `enumerate(...)`
---
## 77. What would you say if asked, “How deep should I prepare Python for
a backend interview?”
For a mid-to-senior backend role, I would prepare in three layers:
First, syntax and fundamentals:
- data types
- loops
- functions
- scope
- exceptions
- comprehensions
- iterables
Second, Python internals and tricky behavior:
- mutability
- object references
- closures
- decorators
- generators
- `is` vs `==`
- copying
- type hints
Third, backend-oriented depth:
- concurrency basics
- async vs threads vs processes
- memory efficiency
- error handling
- clean API design
- testing and maintainability
That usually gives enough depth for both coding and discussion rounds.
---
# Very common rapid-fire questions
## 78. Is Python pass-by-reference?
Not exactly. Python is better described as pass-by-object-reference or
pass-by-assignment.
Functions receive references to objects. If the object is mutable, it can
be modified inside the function.
---
## 79. Are strings mutable in Python?
No, strings are immutable.
Any apparent modification creates a new string.
---
## 80. Can a set contain a list?
No, because list is not hashable.
---
## 81. Can a dictionary key be a tuple?
Yes, if all elements inside the tuple are hashable.
---
## 82. What does `id()` return?
It returns the identity of an object, which is unique for that object
during its lifetime.
---
## 83. What does `sorted()` return?
A new sorted list.
---
## 84. What does `reversed()` return?
An iterator that yields items in reverse order.
---
## 85. Are functions objects in Python?
Yes.
---
## 86. What is the enclosing scope in LEGB?
It is the scope of outer functions surrounding the current local scope.
---
## 87. What happens if you modify a list while iterating over it?
It can lead to skipped elements, unexpected behavior, or bugs. Usually it
is safer to iterate over a copy or build a new list.
---
## 88. What’s more idiomatic: `if len(items) > 0` or `if items`?
Usually `if items` is more idiomatic.
But if distinguishing empty from `None` matters, be explicit.
---
## 89. What is the difference between `remove()` and `pop()` in a list?
`remove(x)` removes the first matching value.
`pop(i)` removes and returns the item at index `i`.
---
## 90. What is the difference between `discard()` and `remove()` in a set?
`remove()` raises `KeyError` if the element is absent.
`discard()` does nothing if the element is absent.
---
# How to use this for interview prep
A strong way to prepare is:
1. Read each question and answer aloud.
2. Try to answer without looking.
3. Write tiny code snippets for tricky topics:
- mutable defaults
- closures
- late binding
- shallow vs deep copy
- `is` vs `==`
4. Practice explaining each one in simple words, not textbook language.
For senior backend interviews, interviewers often care less about
memorized definitions and more about whether you can explain behavior
clearly and avoid production bugs.
I can turn this into:
- a **clean cheat sheet**
- a **top 50 must-know version**
- or a **mock interview Q&A set with follow-up questions and model
answers**