| Variables & Types19 questions |
| 1 | Floor division result | Easy | — |
| 2 | None compared to zero | Easy | — |
| 3 | Augmented assignment on immutable | Easy | — |
| 4 | Which type is mutable? | Easy | — |
| 5 | Adding int and float | Easy | — |
| 6 | String repetition | Easy | — |
| 7 | Variable rebinding changes type | Easy | — |
| 8 | Boolean arithmetic | Easy | — |
| 9 | Chained comparisons | Easy | — |
| 10 | Floor division with negatives | Easy | — |
| 11 | Dividing two ints | Easy | — |
| 12 | Which type is immutable? | Easy | — |
| 13 | Boolean as index | Easy | — |
| 14 | String repetition with zero | Easy | — |
| 15 | Chained equality comparison | Easy | — |
| 16 | Identity vs equality | Medium | — |
| 17 | Walrus operator use case | Medium | — |
| 18 | Walrus operator in a comprehension | Medium | — |
| 19 | Small integer caching | Hard | — |
| Control Flow20 questions |
| 1 | any() and all() short-circuit | Easy | — |
| 2 | Conditional expression (ternary) | Easy | — |
| 3 | Falsy values in Python | Easy | — |
| 4 | Short-circuit evaluation with and | Easy | — |
| 5 | break exits only the innermost loop | Easy | — |
| 6 | zip() stops at the shortest | Easy | — |
| 7 | enumerate() with a start value | Easy | — |
| 8 | match statement (Python 3.10+) | Easy | — |
| 9 | continue skips the rest of the iteration | Easy | — |
| 10 | Purpose of the pass statement | Easy | — |
| 11 | Non-empty container is truthy | Easy | — |
| 12 | Nested ternary expression | Easy | — |
| 13 | enumerate() default start | Easy | — |
| 14 | match with a wildcard | Easy | — |
| 15 | zip() with three iterables | Easy | — |
| 16 | pass inside an if block | Easy | — |
| 17 | for-else clause | Medium | — |
| 18 | Nested list comprehension | Medium | — |
| 19 | for-else with break triggered | Medium | — |
| 20 | Nested comprehension with filter | Medium | — |
| Lists21 questions |
| 1 | Slice creates a shallow copy | Easy | — |
| 2 | append vs extend | Easy | — |
| 3 | Negative indexing | Easy | — |
| 4 | in operator on a list | Easy | — |
| 5 | sort() vs sorted() | Easy | — |
| 6 | list.pop() with no argument | Easy | — |
| 7 | Extended unpacking with * | Easy | — |
| 8 | del vs remove() | Easy | — |
| 9 | append adds a nested list | Easy | — |
| 10 | Negative index with assignment | Easy | — |
| 11 | sort() returns None | Easy | — |
| 12 | pop() return value | Easy | — |
| 13 | in operator with a nested list | Easy | — |
| 14 | Unpacking with star at the front | Easy | — |
| 15 | remove() on duplicates | Easy | — |
| 16 | Mutable default argument trap | Medium | — |
| 17 | List comprehension variable scope | Medium | — |
| 18 | Slicing beyond bounds | Medium | — |
| 19 | Mutable default fixed with None | Medium | — |
| 20 | Generator expression scope | Medium | — |
| 21 | List multiplication with mutable elements | Hard | — |
| Dictionaries22 questions |
| 1 | Dict comprehension | Easy | — |
| 2 | Missing key: [] vs .get() | Easy | — |
| 3 | collections.defaultdict purpose | Easy | — |
| 4 | Merging dicts with update() | Easy | — |
| 5 | dict.pop() vs del d[key] | Easy | — |
| 6 | Unhashable key type | Easy | — |
| 7 | Iterating over a dict | Easy | — |
| 8 | Dictionary key ordering (Python 3.7+) | Easy | — |
| 9 | Updating a key preserves its position | Easy | — |
| 10 | get() with no default | Easy | — |
| 11 | Dict merge with | operator (Python 3.9+) | Easy | — |
| 12 | defaultdict(int) for counting | Easy | — |
| 13 | Dict comprehension with filter | Easy | — |
| 14 | pop() with a default on missing key | Easy | — |
| 15 | Iterating with .items() | Easy | — |
| 16 | Shallow copy of a nested dict | Medium | — |
| 17 | collections.Counter most_common() | Medium | — |
| 18 | setdefault() behavior | Medium | — |
| 19 | Why dict keys must be hashable | Medium | — |
| 20 | setdefault() return value | Medium | — |
| 21 | Counter arithmetic | Medium | — |
| 22 | Deep copy vs shallow copy | Medium | — |
| Functions20 questions |
| 1 | Functions without return | Easy | — |
| 2 | Closure captures variable by reference | Easy | — |
| 3 | *args collects positional arguments | Easy | — |
| 4 | Lambda as sort key | Easy | — |
| 5 | What happens without a base case | Easy | — |
| 6 | Unpacking into function call | Easy | — |
| 7 | map() returns an iterator | Easy | — |
| 8 | Forgetting to return a computed value | Easy | — |
| 9 | Lambda with multiple arguments | Easy | — |
| 10 | Tracing a simple recursive function | Easy | — |
| 11 | filter() is also lazy | Easy | — |
| 12 | LEGB scope lookup | Medium | — |
| 13 | When are default argument values evaluated? | Medium | — |
| 14 | Keyword-only arguments | Medium | — |
| 15 | Generator function with yield | Medium | — |
| 16 | nonlocal keyword | Medium | — |
| 17 | Local variable shadows global | Medium | — |
| 18 | Mutable default argument trap | Medium | — |
| 19 | Exhausted generator raises StopIteration | Medium | — |
| 20 | Calling a keyword-only function positionally | Medium | — |
| Strings18 questions |
| 1 | Strings are immutable | Easy | — |
| 2 | f-string interpolation | Easy | — |
| 3 | Substring check with in | Easy | — |
| 4 | f-string format specifiers | Easy | — |
| 5 | strip() removes leading and trailing whitespace | Easy | — |
| 6 | split() and join() round-trip | Easy | — |
| 7 | str.replace() returns a new string | Easy | — |
| 8 | Case methods return new strings | Easy | — |
| 9 | Triple-quoted string newlines | Easy | — |
| 10 | strip() with a custom character set | Easy | — |
| 11 | split() default splits on whitespace | Easy | — |
| 12 | in checks for substring, not a character set | Easy | — |
| 13 | Triple-quoted string with leading newline | Easy | — |
| 14 | Efficient string building | Medium | — |
| 15 | startswith with a tuple of prefixes | Medium | — |
| 16 | str vs bytes | Medium | — |
| 17 | Why += on strings is slow in a loop | Medium | — |
| 18 | startswith with a tuple of prefixes | Medium | — |
| Comprehensions16 questions |
| 1 | Dict comprehension | Easy | — |
| 2 | Filtering with if | Easy | — |
| 3 | Set comprehension deduplicates | Easy | — |
| 4 | List comprehension basics | Easy | — |
| 5 | Set comprehension from a string | Easy | — |
| 6 | Generator expression vs list comprehension | Medium | — |
| 7 | Ternary inside a comprehension | Medium | — |
| 8 | Dict comprehension from two lists | Medium | — |
| 9 | Comprehension vs map() — readability | Medium | — |
| 10 | Ternary vs filter if in a comprehension | Medium | — |
| 11 | Generator expression consumed once | Medium | — |
| 12 | Nested comprehension — flatten | Hard | — |
| 13 | Nested comprehension with filter | Hard | — |
| 14 | Variable scope in comprehensions | Hard | — |
| 15 | Walrus operator in comprehension | Hard | — |
| 16 | Regular for loop vs comprehension — variable leakage | Hard | — |
| Error Handling17 questions |
| 1 | Basic try/except | Easy | — |
| 2 | Catching the right exception type | Easy | — |
| 3 | finally always runs | Easy | — |
| 4 | finally runs even when no exception occurs | Easy | — |
| 5 | Custom exception class | Medium | — |
| 6 | except Exception vs bare except | Medium | — |
| 7 | else clause on try | Medium | — |
| 8 | Raising exceptions | Medium | — |
| 9 | Re-raising with bare raise | Medium | — |
| 10 | contextlib.suppress | Medium | — |
| 11 | Catching multiple exceptions in one clause | Medium | — |
| 12 | else does not run when exception is raised | Medium | — |
| 13 | Exception hierarchy — BaseException vs Exception | Medium | — |
| 14 | Catching a custom exception by its parent type | Medium | — |
| 15 | Order matters in multiple except clauses | Medium | — |
| 16 | Exception chaining with raise from | Hard | — |
| 17 | with statement as context manager | Hard | — |
| Iterators & Generators15 questions |
| 1 | zip basics | Easy | — |
| 2 | enumerate gives index and value | Easy | — |
| 3 | zip stops at the shortest iterable | Easy | — |
| 4 | enumerate default start | Easy | — |
| 5 | Unzipping with zip(*) | Medium | — |
| 6 | Generator function with yield | Medium | — |
| 7 | StopIteration when exhausted | Medium | — |
| 8 | Generator memory advantage | Medium | — |
| 9 | filter() with None removes falsy values | Medium | — |
| 10 | map() is lazy | Medium | — |
| 11 | Chaining iterables | Medium | — |
| 12 | zip(*) to transpose a matrix | Medium | — |
| 13 | chain.from_iterable | Medium | — |
| 14 | Sending values into a generator | Hard | — |
| 15 | Infinite generator pattern | Hard | — |
| Classes17 questions |
| 1 | __repr__ vs __str__ | Easy | — |
| 2 | Instance variable vs class variable | Easy | — |
| 3 | __init__ basics | Easy | — |
| 4 | Shadowing a class variable with an instance variable | Easy | — |
| 5 | __init__ with a default parameter | Easy | — |
| 6 | Inheritance and super() | Medium | — |
| 7 | @classmethod vs @staticmethod | Medium | — |
| 8 | @property setter | Medium | — |
| 9 | Dunder methods __len__ and __eq__ | Medium | — |
| 10 | @property getter | Medium | — |
| 11 | super() in __init__ | Medium | — |
| 12 | @classmethod as an alternative constructor | Medium | — |
| 13 | dataclass basics | Hard | — |
| 14 | Mutable default argument in __init__ trap | Hard | — |
| 15 | Method resolution order (MRO) | Hard | — |
| 16 | __slots__ purpose | Hard | — |
| 17 | dataclass field with default_factory | Hard | — |
| Functional Tools18 questions |
| 1 | sorted() with key= | Easy | — |
| 2 | sorted() vs list.sort() | Easy | — |
| 3 | lambda basics | Easy | — |
| 4 | list.sort() returns None | Easy | — |
| 5 | Sorting by a field with lambda | Medium | — |
| 6 | lambda limitations | Medium | — |
| 7 | functools.reduce | Medium | — |
| 8 | functools.partial | Medium | — |
| 9 | filter() removes falsy values | Medium | — |
| 10 | functools.lru_cache | Medium | — |
| 11 | reduce with an initial value | Medium | — |
| 12 | partial with positional arguments | Medium | — |
| 13 | lru_cache with unhashable arguments | Medium | — |
| 14 | operator.itemgetter vs lambda | Hard | — |
| 15 | Argument order rules | Hard | — |
| 16 | *args and **kwargs unpacking | Hard | — |
| 17 | Building a dict with zip and dict() | Hard | — |
| 18 | dict comprehension from two lists | Hard | — |
| Decorators18 questions |
| 1 | @ is syntactic sugar | Easy | — |
| 2 | Basic wrapper pattern | Easy | — |
| 3 | Logging decorator output | Easy | — |
| 4 | Decorator that prints after the call | Easy | — |
| 5 | functools.wraps preserves __name__ | Medium | — |
| 6 | Class used as a decorator | Medium | — |
| 7 | Stacking decorators - order of application | Medium | — |
| 8 | Decorator factory with arguments | Medium | — |
| 9 | Memoization decorator | Medium | — |
| 10 | Decorator factory with a prefix argument | Medium | — |
| 11 | Three stacked decorators | Medium | — |
| 12 | Cache shared across two decorated instances | Medium | — |
| 13 | Class decorator storing last argument | Medium | — |
| 14 | Preserving signature for introspection | Hard | — |
| 15 | When decorator code runs | Hard | — |
| 16 | Mutable state in a decorator closure | Hard | — |
| 17 | @staticmethod stacked with a custom decorator | Hard | — |
| 18 | Decorator factory - when each level runs | Hard | — |
| Modules & Packages16 questions |
| 1 | What __init__.py does in a package | Easy | — |
| 2 | import math vs from math import sqrt | Easy | — |
| 3 | What if __name__ == '__main__': does | Easy | — |
| 4 | import alias with 'as' | Easy | — |
| 5 | __name__ value when imported | Easy | — |
| 6 | __all__ and 'from module import *' | Medium | — |
| 7 | Relative imports with 'from . import' | Medium | — |
| 8 | Module vs package - what's the difference | Medium | — |
| 9 | How Python resolves imports via sys.path | Medium | — |
| 10 | Importing the same module twice | Medium | — |
| 11 | __all__ does not hide names from direct import | Medium | — |
| 12 | Namespace packages in Python 3.3+ | Hard | — |
| 13 | importlib.import_module() and when you need it | Hard | — |
| 14 | Circular imports and the standard fix | Hard | — |
| 15 | Deleting from sys.modules and re-importing | Hard | — |
| 16 | Why deferred imports fix circular dependency | Hard | — |
| File I/O17 questions |
| 1 | Why prefer 'with open()' over manual close() | Easy | — |
| 2 | readlines() vs iterating the file object | Easy | — |
| 3 | open() modes: r, w, and a | Easy | — |
| 4 | open() 'x' exclusive creation mode | Easy | — |
| 5 | Iterating a file object vs readlines() | Easy | — |
| 6 | Text mode vs binary mode | Medium | — |
| 7 | json.dump vs json.dumps | Medium | — |
| 8 | pathlib.Path.stem | Medium | — |
| 9 | csv.reader vs csv.DictReader | Medium | — |
| 10 | What open() returns and what happens if you don't close it | Medium | — |
| 11 | json.load vs json.loads | Medium | — |
| 12 | csv.writer vs csv.DictWriter | Medium | — |
| 13 | seek(0) after consuming the file | Hard | — |
| 14 | Reading a binary file in text mode | Hard | — |
| 15 | open('w') on a path whose parent directory doesn't exist | Hard | — |
| 16 | pathlib.Path.glob() - ** vs * | Hard | — |
| 17 | tell() tracks file position | Hard | — |
| Regular Expressions17 questions |
| 1 | What re.findall returns | Easy | — |
| 2 | Raw strings in regex patterns | Easy | — |
| 3 | re.search vs re.match - key difference | Easy | — |
| 4 | re.match anchors to the start | Easy | — |
| 5 | Raw string vs regular string in a pattern | Easy | — |
| 6 | re.compile - when and why | Medium | — |
| 7 | re.sub replacement | Medium | — |
| 8 | Capturing groups and .groups() | Medium | — |
| 9 | re.split on whitespace | Medium | — |
| 10 | Greedy vs lazy quantifiers | Medium | — |
| 11 | re.sub with a count limit | Medium | — |
| 12 | Greedy quantifier on a repeated pattern | Medium | — |
| 13 | Positive lookahead (?=...) | Hard | — |
| 14 | re.DOTALL changes what . matches | Hard | — |
| 15 | Named groups (?P<name>...) | Hard | — |
| 16 | Non-capturing groups (?:...) | Hard | — |
| 17 | Negative lookahead (?!...) | Hard | — |
| Type Hints16 questions |
| 1 | What Optional[str] means | Easy | — |
| 2 | Basic function annotation syntax | Easy | — |
| 3 | Type hints are not enforced at runtime | Easy | — |
| 4 | Union[int, str] vs int | str - version compatibility | Medium | — |
| 5 | list[str] vs List[str] from typing | Medium | — |
| 6 | Callable annotation with arguments | Medium | — |
| 7 | TypedDict for structured dicts | Medium | — |
| 8 | What from __future__ import annotations does | Medium | — |
| 9 | Callable with no fixed arguments | Medium | — |
| 10 | TypeVar - preserving type identity | Hard | — |
| 11 | Protocol - structural vs nominal subtyping | Hard | — |
| 12 | get_type_hints() vs __annotations__ with future annotations | Hard | — |
| 13 | @overload - when Union is not enough | Hard | — |
| 14 | @overload - which body actually runs | Hard | — |
| 15 | Protocol vs ABC - the registration difference | Hard | — |
| 16 | TypeVar bound - restricting the type range | Hard | — |