We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Pattern Matching, f-Strings and Newer Syntax step 15 of 23
Reuse a Computed Value with the Walrus Operator
Code often computes a value, tests it, and then needs the same value again.
The walrus operator := lets you keep the value you compute inside the
test. name := expression stores the result in name and also returns it.
Here you use it in an if, a while loop and a list comprehension.
# In an if: match once, then use the match.
if (found := ENTRY_RE.match(line.strip())) is not None:
level = found["level"]
# In a while loop: read and test in one line.
while block := stream.read(size):
process(block)
# In a comprehension: call compute once per item.
results = [y for x in xs if (y := compute(x)) > 0]
The is not None check tells mypy that found is a match, not None,
inside the branch. Without :=, the comprehension becomes
[compute(x) for x in xs if compute(x) > 0], which calls compute twice for
every item it keeps. A name you assign with := in a comprehension stays set
in the enclosing function afterward, so pick one that no other variable uses.
What to write
Fill in four helpers and solve. Your submission must pass mypy --strict.
parse_log(lines)strips each line and callsENTRY_RE.matchon it once. Skip lines that don't match. Return a list of(level, message)tuples in input order, with the message exactly as the pattern captures it, so"TRACE spaced out"gives("TRACE", "spaced out").chunks(stream, size)readssizebytes at a time untilreadreturns the emptyb"". It is a generator, and eachyieldhands one block to the caller. Don't yield the empty block, and don't close the stream, because it belongs to the caller. The last block can be shorter thansize.select_expensive(items, key, prefix)returns eachkey(item)that starts withprefix, in order, duplicates included. Use one list comprehension, and callkeyexactly once per item, including items that fail the test. Indef select_expensive[T](...),Tstands for whatever item type the caller passes.dedupe_expensive(items, key)returns the first original item for each distinctkey(item). Callkeyexactly once per item, duplicates included. Use aforloop and a set of the keys seen so far.
items can be any iterable, so loop over it only once.
Build the report in solve
Wrap blob in io.BytesIO and pass it to chunks. Make two key functions,
one for select_expensive and one for dedupe_expensive. Each returns
value.strip().lower() and counts its own calls. Pass prefix unchanged, so
a prefix of "A" matches none of the lowercase keys. Return a dictionary
with these keys:
| Key | Value |
|---|---|
entries |
The list from parse_log(lines) |
chunks |
The length of each block, in order |
selected |
The list from select_expensive |
deduped |
The list from dedupe_expensive |
select_calls |
How many times the key function for select_expensive ran |
dedupe_calls |
How many times the key function for dedupe_expensive ran |
For items ["Apple", " apple", "beta"] and prefix "a", selected is
["apple", "apple"], deduped is ["Apple", "beta"], and both counts are 3.
Edge cases
- An empty prefix matches every key, including an empty string.
- Empty
itemsgive empty lists and zero key calls. - An empty
blobgives no blocks, after onereadthat returnsb"". sizeis always at least 1.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.