These independent assignments use synthetic data. Try them first, then check edge cases and open the hint. Time is an estimate; allow additional time for project tests and documentation.
Choose your practice · Interview mistakes
Scroll the table horizontally →
Two guests, separate preferences
A café stores the template {"allergens": ["nuts"], "alerts": {"email": True}}. Implement new_preferences(template). Create preferences for two guests; add milk and disable email for the first guest. The second guest and the template must keep their original values. Then investigate a function with allergens=[]: why can two calls share a list? Demonstrate == and is on your objects.
Check your result
- Nested lists and dictionaries are independent; test each level.
- Cover an empty list, repeated calls and a list inside a tuple separately.
- Explain why copying the outer dictionary does not copy its nested objects.
Hint — after your attempt
Draw which variables refer to the same object.
Extension: Add optional preferences without a mutable default argument.
Repeated order events
A scanner sent [0, 14, 14, 7, 0, 19, 7]. Implement unique_order_ids(ids): preserve first-occurrence order and return [0, 14, 7, 19]. Zero is a valid identifier. Do not mutate the input list. Explain runtime and extra memory for a large stream.
Check your result
- Empty input produces an empty result.
- Handle duplicates and 0 without sorting or using truthiness as membership.
- Measure runtime growth for 10,000 and 100,000 items.
Hint — after your attempt
Separate output order from the membership check.
Extension: Accept any finite iterable, including a one-shot generator.
The largest order without hidden losses
An order report contains integer minor-unit amounts: [0, -250, 980, 980, 410]. Return the first position of the maximum: (2, 980). Negative amounts represent refunds and are valid. Return None for empty input; for bool values and strings, raise ValueError. Next, find pairs of distinct positions whose amounts differ by at least a given threshold; explicitly distinguish position pairs from unique value pairs.
Check your result
- Handle all-negative input and tied maxima.
- For
[10, 10, 40]and threshold 30, there are two position pairs and one value pair. - Reject a negative threshold and explain pair-search complexity.
Hint — after your attempt
Initializing the maximum to zero fails for a list of refunds.
Extension: Compare nested loops with a sorted approach, including sorting cost.
A seating plan without shared rows
Build a rectangular seating grid rows × cols, numbered row by row from start. For (2, 3, 11), return [[11, 12, 13], [14, 15, 16]], row sums [36, 45] and column sums [25, 27, 29]. Dimensions must be positive integers. Explain what happens when constructing the grid by repeating one list; test it by replacing a single seat.
Check your result
- Numbers are unique and consecutive.
- Replacing a cell does not affect other rows.
- Cover 1×1, 1×4 and invalid dimensions.
Hint — after your attempt
Check whether grid rows are the same object.
Extension: Accept unavailable seat numbers and sum only available seats.
Find a dish by a short code
A register matches a code as a subsequence of a dish name: characters must appear in order, with gaps allowed. Use ASCII letters only and ignore case. matches("tea", "steak") is True; matches("tea", "eat") is False. An empty code matches any name. Implement the check and explain why comparing sets of characters is insufficient.
Check your result
- Repeated letters retain their count and order requirements.
aadoes not matcha;aamatchesbanana.- Scan the name once.
Hint — after your attempt
Track the next code character to match.
Extension: Add a separate contiguous-substring mode and demonstrate the difference with tests.
Clean a kitchen note
Implement clean_note(text): remove only the literal tokens :-) and :-(, then replace the first and last ! with a dot. A single ! is replaced once. Preserve all other characters and spaces. "Hot! :-) urgent!!" becomes "Hot. urgent!.". Implement another function that deduplicates a dish code while preserving first occurrence: "abacb" → "abc".
Check your result
- Cover empty input, no ! and a single !.
- Do not remove ordinary parentheses or colons.
- Keep the two spaces in the example.
Hint — after your attempt
Separate token removal from locating the first and last positions.
Extension: Explain how whitespace normalization would change the contract; do not add it silently.
Compress display signals
A kitchen display records string statuses. Compress adjacent equal statuses into (status, count) pairs: ["ready", "ready", "busy", "ready"] → [("ready", 2), ("busy", 1), ("ready", 1)]. Also implement decompression. Statuses may contain digits and delimiters; keep the representation unambiguous.
Check your result
- Do not combine equal statuses separated by a different status.
- Decompressing compressed input reproduces the original list.
- Reject zero, negative and non-integer counts when decompressing.
Hint — after your attempt
Keep the current value and repetition count separately.
Extension: Make a streaming generator that does not retain the entire input.
Reverse an allergen directory
Reverse {"dish-7": "nuts", "dish-2": "milk", "dish-9": "nuts"} into {"nuts": ["dish-7", "dish-9"], "milk": ["dish-2"]}. Preserve input order within each list. Next, process {"lunch": {"dish-7": 2}, "dinner": {"dish-7": 1}}: emit full-path records without losing identical keys from different branches.
Check your result
- Colliding values are not overwritten.
- The nested example produces different paths:
(lunch, dish-7)and(dinner, dish-7). - Cover empty input and depth greater than two; define allowed leaf types.
Hint — after your attempt
The reverse mapping has multiple values per key.
Extension: Add code renaming with an explicit error when new keys collide.
A menu item in a set
Create an immutable MenuItem(menu_id, code, title). Equality and hashing depend only on (menu_id, code); titles may differ. The same code in two menus denotes different items. Add clear str and repr; show an individual object and a list of objects.
Check your result
- Equal objects have equal hashes and deduplicate in a set.
- Fields cannot change after insertion into a set.
- Handle comparison with an unrelated type correctly.
Hint — after your attempt
Define the domain identity of a menu item first.
Extension: Explain why a list display uses a different representation method than printing one object.
Container packs for an order
A kitchen has one pack of 6 containers and two packs of 4. Implement a callable PackStock: a request selects whole packs totaling exactly the requested quantity and reduces stock. A request for 8 uses the two packs of 4; a request for 5 fails without changing stock. Minimize the number of packs; break ties by preferring larger packs. Sizes and requested quantities are positive integers; zero stock is valid.
Check your result
- A greedy largest-pack choice must not lose the solution for 8.
- Do not dispense more packs than are in stock.
- A failed search leaves no partial mutation.
Hint — after your attempt
Separate combination search from applying the result to inventory.
Extension: Set input-size limits and explain when another algorithm is needed.
A diamond in a handler hierarchy
Create Base, Audit(Base), Cache(Base) and Endpoint(Audit, Cache). Each handle() appends its class name to a shared trace; intermediate classes call super().handle(), while Base ends the chain. Predict the call order and verify it using Endpoint.__mro__. Fix a version where Audit calls Base directly and skips Cache. Demonstrate class versus instance attributes using an audit log list.
Check your result
- Order: Endpoint, Audit, Cache, Base; Base is called once.
- Swapping base classes changes the order predictably.
- Instance logs do not accidentally mix.
Hint — after your attempt
In a super chain, the next class follows the concrete object’s MRO.
Extension: Compare this hierarchy with composing independent handlers.
Register notification types
Given {"email": {"retry_limit": 2}, "screen": {"retry_limit": 0}}, create a handler type for each key using a regular class factory, then show an equivalent using type(). Instances must have separate message queues. Reject duplicate type registration explicitly. Discuss when dynamic classes are inferior to a handler dictionary, and why a Singleton in one Python process does not coordinate multiple processes.
Check your result
- Names and retry_limit match configuration, including 0.
- Queues are independent and duplicate registration fails.
- Explain the design limits without claiming a global Singleton.
Hint — after your attempt
Do not store a mutable queue as an attribute of the generated class.
Extension: Validate the entire configuration before creating any type.
Each callback sends its own status
Build three callbacks for queued, cooking and ready inside a loop. After the loop finishes, each callback must return its own status and the supplied order_id. Demonstrate the broken version where all return ready, explain when the variable is bound, and fix it in two ways. In the public function, make order_id positional and status keyword-only.
Check your result
- Three callbacks produce three different statuses for one order_id.
- The function signature rejects positional status.
- Do not replace a sender exception with a generic success.
Hint — after your attempt
Compare closing over a variable with capturing its current value in a separate scope.
Extension: Write tests that call callbacks after registration completes.
Rotate kitchen shifts
Implement cycle_staff(names, start=0), yielding names indefinitely in a cycle. Input is a finite collection, snapshotted when the iterator is created. For ["A", "B", "C"] and start=1, the first five values are B, C, A, B, C. Empty input terminates without yielding. Add a finite wrapper that takes at most n shifts.
Check your result
- Mutating the input after iterator creation does not change the schedule.
- Zero n gives an empty result; reject negative n.
- Do not materialize an infinite list.
Hint — after your attempt
A generator function starts executing on the first next; account for snapshot timing.
Extension: Add a generator of cumulative shift counts per staff member.
Stream receipt-line totals
Each file line contains dish_id;quantity;price_minor. Example: 7;2;125, 9;1;300, 7;1;125. Implement a record generator and compute the total: 675. Skip blank lines. An invalid line raises an error including its line number; quantity is a positive integer and price is a nonnegative integer. The file may exceed available memory.
Check your result
- The example totals 675; zero-price lines are valid.
- Error numbers refer to the original file, including blank lines.
- Closing the iterator releases the file; do not load it all at once.
Hint — after your attempt
Separate parsing one line from owning the file resource.
Extension: Return per-dish totals and explain the resulting memory bound.
Audit a function result
Implement audit(operation, sink) for a synchronous function. The sink receives exactly one record: operation, outcome (ok or error) and duration. Preserve function arguments and return values; propagate its exception. Do not include passwords or argument values in the record. Use a monotonic clock; the sink does not raise exceptions in this exercise.
Check your result
- Success and failure each produce one record.
- Preserve metadata with wraps.
- Tests replace the clock and sink without sleeping.
Hint — after your attempt
Identify what must happen on both success and failure.
Extension: If the sink can fail, explicitly define which result the caller sees.
Publish a report atomically
Implement the report_writer(path) context manager. Write a temporary file in the same directory. On successful exit, replace the previous report; on error, keep the old report, delete the temporary file and propagate the exception. State the guarantee for one process and normal completion; power-loss durability is a separate extension.
Check your result
- The old report remains fully readable before exit.
- A mid-write exception leaves the old file intact.
- No open handles or temporary leftovers remain after success or failure.
Hint — after your attempt
The temporary file lifecycle and destination replacement are separate steps.
Extension: Analyze two concurrent writers and define the extra guarantee required.
Collect supplier prices asynchronously
Implement collect_quotes(suppliers, fetch, limit, timeout): at most limit fetch calls run concurrently. Preserve supplier order and represent each call’s success or error separately. Start each positive per-supplier timeout after acquiring an execution slot; cancellation of the entire operation must cancel its tasks and propagate. Limit is a positive integer. Add an async duration decorator and demonstrate why synchronous sleep blocks the event loop.
Check your result
- A test fetch records peak active calls; it never exceeds limit.
- One failure does not discard successes; cancellation is not disguised as an ordinary error.
- No tasks remain afterwards; tests control clocks and delays.
Hint — after your attempt
Separate a supplier failure from cancellation of the whole operation.
Extension: For CPU-heavy work, compare the event loop, a thread and a process using measurements.
A ticket checksum
A ticket number is a nonnegative integer without leading zeros. Select numbers whose decimal digit sum is divisible by 7. For [0, 7, 16, 25, 34, 99], return [0, 7, 16, 25, 34]; preserve order and duplicates. Reject strings, booleans and negative numbers. Show integer-division/remainder and string-conversion approaches, then compare them.
Check your result
- Handle zero explicitly; it qualifies.
- Include every digit of a multi-digit number.
- Explain complexity by digit count, not just ticket count.
Hint — after your attempt
The remainder modulo 10 gives the current last digit.
Extension: Yield qualifying tickets in an inclusive range without materializing the entire range.
Count tasting-menu combinations
Choose k of n distinct dishes without replacement; serving order does not matter. Implement menu_combinations(n, k) with an exact integer result. (5, 2) gives 10 and (0, 0) gives 1. Allow 0 ≤ k ≤ n ≤ 200; reject booleans and non-integers. Compare factorial-based calculation, a reduced product and a table for repeated queries. Do not use floating-point intermediate values.
Check your result
- Test k=0, k=n and symmetry between k and n−k.
- Invalid ranges raise explicit errors.
- For repeated queries, measure redundant work and cache memory.
Hint — after your attempt
Identify factors that cancel before computing large factorials.
Extension: Generate all values for one n and verify their sum: 2**n.