"""Day 2 · Block 5 · Pythonic 写法、迭代与类型注解
学习目标:用推导式、sorted(key=)、any/all、enumerate 把循环写短写清楚;
会写生成器函数与 match 语句;给每个函数补上完整类型注解。
用法:uv run python exercises/day2/05_pythonic.py
做法:把每个 TODO 换成你的实现,反复运行直到全部 [OK]。
卡住 8 分钟以上再按 ai-guide.md 的模板提问;拿到提示后自己重写。
预测练习(先在纸上写出输出,再到 REPL 验证):
>>> print([x * 2 for x in range(3)], {x % 3 for x in range(10)})
>>> print({w: len(w) for w in ["a", "bb"]})
>>> g = (x * x for x in range(3))
>>> print(next(g), next(g), next(g)) # 再 next(g) → StopIteration
>>> print(sorted(["b", "A", "c"]), sorted(["b", "A", "c"], key=str.lower))
>>> print(sorted([("a", 3), ("b", 1)], key=lambda t: t[1]))
>>> print(any(x > 5 for x in [1, 7]), all(x > 5 for x in [1, 7]))
"""
from collections.abc import Iterator
from typing import Any
# ---- 任务 1 ----
def squares_of_evens(nums: list[int]) -> list[int]:
"""偶数的平方(用列表推导式一行完成)。例:[1, 2, 3, 4] -> [4, 16]"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 2 ----
def word_length_map(words: list[str]) -> dict[str, int]:
"""词 -> 词长的字典(用字典推导式)。
例:["hi", "hey"] -> {"hi": 2, "hey": 3}
"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 3 ----
def flatten(matrix: list[list[int]]) -> list[int]:
"""把二维列表拉平(用嵌套推导式一行完成)。
例:[[1, 2], [3], []] -> [1, 2, 3]
"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 4 ----
def sort_by_score(
records: list[dict[str, Any]], reverse: bool = True
) -> list[dict[str, Any]]:
"""按 record["score"] 排序,返回新列表,不修改入参。
要求用 sorted(..., key=lambda r: r["score"])。
例:[{"n": "a", "score": 1}, {"n": "b", "score": 5}] -> b 在前
"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 5 ----
def all_passed(scores: list[int], threshold: int = 60) -> bool:
"""是否全部达到 threshold(用 all)。例:[60, 70] -> True"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 6 ----
def any_perfect(scores: list[int]) -> bool:
"""是否有满分 100(用 any)。例:[99, 100] -> True"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 7 ----
def countdown(n: int) -> Iterator[int]:
"""生成器:依次 yield n, n-1, ..., 0。
例:list(countdown(3)) -> [3, 2, 1, 0]
"""
# TODO: 在这里实现(用 yield 或 yield from,不要 return 列表)
raise NotImplementedError
# ---- 任务 8 ----
def chunks(items: list[Any], size: int) -> Iterator[list[Any]]:
"""生成器:把 items 切成每段 size 个,最后一段可能不足。
size <= 0 时抛出 ValueError("size 必须为正")。
例:list(chunks([1, 2, 3, 4, 5], 2)) -> [[1, 2], [3, 4], [5]]
"""
# TODO: 在这里实现(用 yield)
raise NotImplementedError
# ---- 任务 9 ----
def even_sum_below(limit: int) -> int:
"""小于 limit 的偶数之和(用 sum(生成器表达式))。例:10 -> 20"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 10 ----
def describe_command(cmd: str) -> str:
"""解析一条命令,必须用 match cmd.split(): 实现。
["add", a, b] -> f"结果:{int(a) + int(b)}"
["greet", name] -> f"你好,{name}"
["quit"] -> "再见";[] -> "空命令";其他 -> "未知命令"
例:"add 3 4" -> "结果:7"
"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 11 ----
def find_user(users: list[dict[str, Any]], name: str) -> dict[str, Any] | None:
"""按 name 查用户,找不到返回 None(可用 next(..., None))。
例:find_user([{"name": "小明"}], "小刚") -> None
"""
# TODO: 在这里实现
raise NotImplementedError
# ---- 任务 12 ----
def numbered(words: list[str]) -> list[tuple[int, str]]:
"""给每个词编号,从 1 开始(用 enumerate(start=1))。
例:["a", "b"] -> [(1, "a"), (2, "b")]
"""
# TODO: 在这里实现
raise NotImplementedError
# ====================== 自测:不要改动下面的代码 ======================
def _check_squares_of_evens() -> None:
assert squares_of_evens([1, 2, 3, 4]) == [4, 16], (
"squares_of_evens([1,2,3,4]) 应为 [4, 16]"
)
assert squares_of_evens([]) == [], "空列表应返回空列表"
def _check_word_length_map() -> None:
assert word_length_map(["hi", "hey"]) == {"hi": 2, "hey": 3}, (
'word_length_map(["hi","hey"]) 应为 {"hi": 2, "hey": 3}'
)
def _check_flatten() -> None:
assert flatten([[1, 2], [3], []]) == [1, 2, 3], (
"flatten([[1,2],[3],[]]) 应为 [1, 2, 3]"
)
def _check_sort_by_score() -> None:
data = [{"n": "a", "score": 1}, {"n": "b", "score": 5}]
got = sort_by_score(data)
assert [r["n"] for r in got] == ["b", "a"], "默认降序,b 应在前"
assert [r["n"] for r in sort_by_score(data, reverse=False)] == ["a", "b"], (
"reverse=False 时应升序"
)
assert [r["n"] for r in data] == ["a", "b"], "不能修改入参 records"
def _check_all_passed() -> None:
assert all_passed([60, 70]) is True, "[60, 70] 应为 True"
assert all_passed([59, 100]) is False, "[59, 100] 应为 False"
assert all_passed([]) is True, "空列表的 all 为 True"
def _check_any_perfect() -> None:
assert any_perfect([99, 100]) is True, "[99, 100] 应为 True"
assert any_perfect([99, 98]) is False, "[99, 98] 应为 False"
def _check_countdown() -> None:
assert list(countdown(3)) == [3, 2, 1, 0], "countdown(3) 应为 [3, 2, 1, 0]"
assert list(countdown(0)) == [0], "countdown(0) 应为 [0]"
def _check_chunks() -> None:
assert list(chunks([1, 2, 3, 4, 5], 2)) == [[1, 2], [3, 4], [5]], (
"chunks([1,2,3,4,5], 2) 应为 [[1,2],[3,4],[5]]"
)
try:
list(chunks([1, 2], 0))
except ValueError:
pass
else:
raise AssertionError("size <= 0 时应抛出 ValueError")
def _check_even_sum_below() -> None:
assert even_sum_below(10) == 20, "even_sum_below(10) 应为 20"
assert even_sum_below(1) == 0, "even_sum_below(1) 应为 0"
def _check_describe_command() -> None:
assert describe_command("add 3 4") == "结果:7", '"add 3 4" 应为 "结果:7"'
assert describe_command("greet 小明") == "你好,小明", "greet 分支不对"
assert describe_command("quit") == "再见", '"quit" 应为 "再见"'
assert describe_command("") == "空命令", '"" 应为 "空命令"'
assert describe_command("jump") == "未知命令", '"jump" 应为 "未知命令"'
def _check_find_user() -> None:
users = [{"name": "小明", "age": 15}, {"name": "小红", "age": 16}]
assert find_user(users, "小红") == {"name": "小红", "age": 16}, "应找到小红"
assert find_user(users, "小刚") is None, "找不到时应返回 None"
def _check_numbered() -> None:
assert numbered(["a", "b"]) == [(1, "a"), (2, "b")], "编号应从 1 开始"
assert numbered([]) == [], "空列表应返回空列表"
CHECKS = [
_check_squares_of_evens,
_check_word_length_map,
_check_flatten,
_check_sort_by_score,
_check_all_passed,
_check_any_perfect,
_check_countdown,
_check_chunks,
_check_even_sum_below,
_check_describe_command,
_check_find_user,
_check_numbered,
]
def _run_checks() -> None:
passed = 0
for check in CHECKS:
name = check.__name__.removeprefix("_check_")
try:
check()
except NotImplementedError:
print(f"[TODO] {name}: 还没实现")
except AssertionError as e:
print(f"[FAIL] {name}: {e}")
except Exception as e:
print(f"[ERROR] {name}: {type(e).__name__}: {e}")
else:
passed += 1
print(f"[OK] {name}")
total = len(CHECKS)
tail = ",本文件全部完成!" if passed == total else ""
print(f"\n{passed}/{total} 通过{tail}")
if __name__ == "__main__":
_run_checks()