26S1
26S2
26fall 的同学们其实在手搓coding的压力会大起来,但是interview会减少很多
以这张图为例,事实上重复了一套的assignmentent,总共依旧是6个作业加两个interview,最开始的interview是占整个assignmentent一半的分的,我就是因为这个原因,导致一个没有HD 我的Coding部分都是80%,所以相较于上半年的同学们解释能力可以放轻松点,但是code需要加倍努力
这多的15分应该是属于assignment的.其实按照我下面的攻略而言的话一般都会解决这些问题,并不困难不用把9136想成洪水猛兽。
先来讲讲 Assignment 1 是个怎么样的形式:首先会有三个小 subtask 需要你做,但是这三个小的 subtask 不计入成绩当中去,最重要的还是以最后的 task 为主。这导致有些人可能想说我能否直接跳过前面三个 subtask,直接去做最后的 task 呢?答案是不能的,因为最后的 task 是需要调用前面三个 subtask 的函数的,所以你必须把前面三个 subtask 都做完才能去做最后的 task。也就是说前面的 subtask 是和后面的相关联的。
总结下 Assignment 1 的核心是把 Python 基础语法写稳。这一阶段不要急着追求复杂写法,重点是把 input()、print()、变量、类型转换、四则运算、取整除、取余、if/elif/else、字符串切分、列表循环、字典和函数签名写准确。题目通常会给很明确的输入输出格式,最重要的是逐字对齐 expected output,并且函数题不要在函数内部乱用 input() 或 print()。
举个例子吧:现在有个摩托的价格需要算出来,题目如下:
Welcome to the motor line item test script. Motor price: $22.99 How many motors would you like to buy: 10 Total price: $229.90
那么 numerically 就需要把这个题目拆成几个小步骤:
Welcome to the motor line item test script.Motor price: $22.99input() 函数来获取用户输入的数量,如果最后输出的是 float 就得 input 给转换成 float。22.99 * 10subtask 1.2 同理 例子为:
| Product Name | Price |
|---|---|
| motor | $22.99 |
| sensor | $65.75 |
| frame | $70.10 |
| cpu | $95.50 |
进行拆分:
products = ['motor', 'sensor', 'frame', 'cpu'],以及 prices = [22.99, 65.75, 70.10, 95.50]。print() 函数打印 '-' 和字符串 "products name | price",最后再打印一段 '-',搭建好基础框架。products 和 prices 列表:使用 len(products) 获取列表长度(4),用 range(4) 生成序列 0, 1, 2, 3,利用 for i in ... 让循环变量 i 作为索引访问列表元素。i,分别从 products 和 prices 中取出值,赋值给 current_products 和 current_prices。print(f"{current_products:<12} | ${current_prices:.2f}")。
{current_products:<12}:产品名称靠左对齐,固定占 12 个字符宽度(不够补空格),确保竖线对齐。|:原样输出竖线分隔符。$:原样输出美元符号。{current_prices:.2f}:价格保留 2 位小数输出(如 120.00)。subtask 1.3
主要考察的是 if,else 和 elif。
题目为:Your boss wants you to undertake one last exploration... A conditional discount calculator. You are to write a simple program that prompts the user for the end sales price and applies a conditional discount. The discounts are as follows: 30% for orders over $500.00, 15% for orders over $200.00, and 5% for orders over $50.00.
Welcome to the discount calculator. Enter sales amount(dollars): 10.00 or 51.00 or 201.00 or 501.00 Discounted price: $10.00 or $48.45 or $170.85 or $350.70
解析:
Welcome to the discount calculator.input() 函数获取用户输入的销售金额,并将其转换为浮点数。最后的大作业: TASK 1 Quote Calculator (Assessed)
这里的作业要求你怎么通过 code 计算提供的材料,然后所有的 coding 逻辑都是基于之前所学的。
题目为:Your boss now wants you to take what you have learned and create a functional quote calculator for the Smart Maker Components division. Your boss would like you to formalise what you did in subtask 1.2 by creating two aligned lists product_name, containing a list of product names, and product_price, containing a list of product prices. You should populate this list using the table below.
| Product Name | Price |
|---|---|
| stepper | $18.50 |
| display | $24.99 |
| nozzle | $8.20 |
| motherboard | $115.00 |
Welcome to the Smart Maker Quote Calculator. For each product below, please specify your required quantity. stepper: 1 display: 2 nozzle: 5 motherboard: 1 Please see your quote below. stepper: 1 x $18.50 = $18.50 display: 2 x $24.99 = $49.98 nozzle: 5 x $8.20 = $41.00 motherboard: 1 x $115.00 = $115.00 Subtotal: $224.48 Discount: $11.22 Total: $213.26
Welcome to the Smart Maker Quote Calculator. For each product below, please specify your required quantity. stepper: 8 display: 10 nozzle: 20 motherboard: 5 Please see your quote below. stepper: 8 x $18.50 = $148.00 display: 10 x $24.99 = $249.90 nozzle: 20 x $8.20 = $164.00 motherboard: 5 x $115.00 = $575.00 Subtotal: $1136.90 Discount: $170.54 Total: $966.36
解析:
product_name 和 product_price。Welcome to the Smart Maker Quote Calculator. 还有 For each product below, please specify your required quantity.;接着创建一个空列表专门用来存放数量,再通过循环遍历所有产品名称,使用 input() 动态获取输入。关键点:使用 int() 转成整数后通过 .append() 追加到列表中。subtotal = 0.0 累加总价,使用 for i in range(len(product_name)): 提取名称、单价和数量,计算单项总价后通过 subtotal += line_total 进行累加。if-elif-else 结构实现条件判断,按从大到小的顺序(>1500 -> >1000 -> >300)进行梯级判定,避免条件覆盖。题目背景与要求:
RoboWorks 正在开发一套机器人调度系统。Task 1 的目标是实现系统的数据加载、基础校验、任务可行性检查与评估报告生成。整个任务分为四个步骤,你需要根据以下规格说明实现相应的处理逻辑。
Task 1 规格与功能要求(Specification):
Step 1 & Step 2: Data Loading and Validation Each function should: - Read data from the corresponding CSV file - Store the data using aligned lists in a type that is consistent with the data being stored. - Ensure that corresponding indices refer to the same record - Print a warning message to standard error when encountering invalid records, e.g.: Warning: Package P6 has invalid weight (-4). Step 3: Task Feasibility Check To determine if a task is executable, create a function named is_task_executable. This task should take the following parameters, in this order: - task_id - package_ids - package_weights - robot_ids - max_loads - robot_zones - destination_ids - destination_zones - task_ids - source_ids - target_ids - task_package_ids You should infer the types of the input variables from the name of the parameters. Step 4: Report Generation & Main Integration Generate a output file named "feasibility_report.txt" with the following format: Task Feasibility Report T1: executable T2: executable T3: not executable T4: executable Executable tasks: 3 Non-executable tasks: 1 Main function signature: main(robots_path, destinations_path, packages_path, tasks_path, report_path)
作业逻辑与解题拆解:
destinations 和 packages,因为后续在读取 tasks 时需要拿到已经校验过的 ID 列表来进行交叉比对(Cross-referencing)。数据校验不合规时,要使用 print(..., file=sys.stderr) 打印 Warning 并使用 continue 跳过当前行。例如校验重量:
if weight < 0:
print(f'Warning: Package {p_id} has invalid weight ({weight}).', file=sys.stderr)
continue
.index() 找到当前任务对应的起点、终点和包裹重量,然后遍历所有机器人。匹配条件必须同时包含三点:机器人位置等于起点区域、等于终点区域,且最大载重大于等于包裹重量:
if r_zone == source_zone and r_zone == target_zone and r_load >= pkg_weight:
return True
只要找到一台符合条件的机器人就立即返回 True;如果遍历完毕均不满足则返回 False。
write_feasability_report 中以 'w' 模式打开文件,按照格式依次写入各任务的判定结果,并累加 executable_count 和 non_executable_count 最终输出统计总数。最后在 main() 中按顺序组织调用整个流程。整个 Task 1 的核心解题思想可总结为:“校验拦截在前,关联映射在中,逻辑判定在后,格式输出收尾”。下面结合具体的实现考点进行深度拆解:
import sys)题目要求在遇到非法数据记录(Invalid Records)时向标准错误流输出警告,而不是直接报错终止程序。Python 默认的 print() 是输出到标准输出流 (stdout),因此我们需要导入 sys 模块,并在调用时加上 file=sys.stderr 参数:
import sys
# 示范:将警告信息定向输出到标准错误流,避免打断正常程序执行
print(f'Warning: Package {p_id} has invalid weight ({weight}).', file=sys.stderr)
在数据读取阶段,我们使用了对齐列表(Aligned Lists)的数据结构,即不同属性存放在不同列表中,通过相同的索引 $i$ 互相映射。解题逻辑分为以下关键点:
readlines()[1:] 切片避开 CSV 第一行的列名,并通过 .strip().split(',') 去除换行符并切分成数据数组。同时将字符串正确强转为对应的类型(如 int(battery)、float(load))。if 检查。只要有任意一项校验未通过,立即通过 print(..., file=sys.stderr) 报出 Warning,并配合 continue 跳过当前行,确保只有 100% 合规的数据才能追加(.append())到列表中:
read_robots:校验电池电量范围 0 <= battery <= 100、载重 load >= 0、区域必须为非空且纯大写字母(zone.isalpha() and zone.isupper())。read_destinations:校验目的地区域代码是否全大写。read_packages:校验包裹重量是否非负 (weight >= 0)。read_tasks 函数中,我们需要额外的参数 destination_ids 和 package_ids。这是因为任务中的起点 s_id、终点 target_id 以及包裹 p_id 必须是前面已经通过校验的合法 ID。如果不在合规列表中(s_id not in destination_ids),则直接判为非法 Task 并跳过。is_task_executable)这个函数是整个 Task 1 的判定大脑,逻辑非常严密,主要分为四大步骤:
task_id 是否存在。若存在,通过 task_ids.index(task_id) 获取当前任务在列表中的索引 t_idx,并顺藤摸瓜提取出该任务的起点 ID (s_id)、终点 ID (t_id) 和包裹 ID (p_id)。destination_ids.index(s_id) 和 .index(t_id) 查出起点与终点所在的区域名称 (source_zone 和 target_zone);利用 package_ids.index(p_id) 查出当前包裹的实际重量 (pkg_weight)。for i in range(len(robot_ids)) 逐个检查可用的机器人。要成功执行任务,必须同时满足以下三个硬性条件:
# 条件 1: 机器人当前区域必须与任务起点区域一致
# 条件 2: 机器人当前区域必须与任务终点区域一致(即起点终点需在同一区域)
# 条件 3: 机器人的最大载重量必须大于或等于包裹重量
if r_zone == source_zone and r_zone == target_zone and r_load >= pkg_weight:
return True # 只要找到任意一台符合条件的机器人,立刻返回 True 终止循环
False。main)write_feasability_report): 使用 open(file_path, 'w') 以覆盖写入模式打开文件。使用 for 循环同时读取任务 ID 和对应的布尔值结果,根据布尔值累加 executable_count 与 non_executable_count 计数器,格式化写入每行状态(如 T1: executable),最后在文件末尾输出统计汇总,并调用 .close() 释放资源。main Execution Order): 在 main() 函数中,执行顺序至关重要:必须先调用 read_destinations 和 read_packages 获取合规 ID 列表,然后再调用 read_tasks 进行交叉验证。拿到所有清洗后的数据后,遍历任务列表收集判定结果,最后统一传给 write_feasability_report 输出文件。if __name__ == "__main__":): 将测试调用的 main(...) 放在脚本入口保护块中,这样既方便我们自己本地运行测试,又能保证提交给自动评分脚本 (Auto-grader) 导入时不会触发意外执行。题目背景与核心目标:
数字诗歌工作室(Digital Poetry Studio)希望开发一个简易的诗歌生成器。Task 1 的目标是实现系统的文本读取清洗、诗歌切分、Token 化以及 k-gram N-gram 频率模型的统计构建,为后续 Task 2 的生成奠定数据基础。
Task 1 规格与功能要求(Specification):
Step 1: Text Preprocessing & Cleaning - read_text(file_path): 读取文本文件。需拦截 FileNotFoundError;若去除空格后文本为空,抛出 ValueError。 - clean_text(text): 将文本转为小写,并清除除逗号 (,) 和句号 (.) 之外的所有标点符号。若输入非字符串,抛出 TypeError。 Step 2: Build k-gram Model - build_kgram_model(text, k): 1. 校验输入合法性(k 为正整数且非 bool,text 为字符串)。 2. 清洗文本并将逗号与句号替换为前后带空格的形式 (如 " , " 和 " . ")。 3. 识别数字行(如 "1", "2")作为诗歌边界,在每首诗结尾追加 "" 标识符。 4. 遍历所有 Token,使用长度为 k 的滑动窗口统计每个 (Context) -> Next_Word 的频次,返回嵌套字典。 5. 若无法生成任何 k-gram,抛出 ValueError。 Step 3: Query Options - get_next_token_options(kgram, model): 查询特定 k-gram 元组在模型中的下一个 Token 频次字典。若不存在则安全返回空字典 {}。 Step 5: Unit Testing - 编写 unittest 单元测试,涵盖逻辑清洗、模型频次统计、诗歌边界切割、异常输入拦截以及文件读取异常。
待完成的核心任务(Implementation Tasks):
read_text(file_path):实现文本加载与文件边界防护。clean_text(text):实现保留指定标点(逗号、句号)的文本清洗。build_kgram_model(text, k):实现诗歌边界标记 <END> 追加、Token 拆分与滑动窗口建模。get_next_token_options(kgram, model):实现模型 Key 的安全检索。TestKgramModel(unittest.TestCase):实现完整的自动化单元测试集。在 Task 1 的实现中,我们的核心思维路径是:“严密校验在前,标点分离在中,边界识别在后,滑动窗口收尾”。下面结合完整实现代码,逐模块拆解解题逻辑:
read_text & clean_text)read_text): 使用 try...except FileNotFoundError 捕获文件缺失,并抛出自定义提示;利用 content.strip() 校验文件内容,若为空或全为空白字符则主动抛出 ValueError。clean_text):
先通过 isinstance(text, str) 拦截非字符串输入。使用 Python 内置的 string.punctuation 遍历所有标点符号,通过 symbol != ',' and symbol != '.' 显式保留逗号与句号,其余标点全部使用 .replace(symbol, '') 剔除。
# 保留逗号与句号,其余标点剔除
for symbol in string.punctuation:
if symbol != ',' and symbol != '.':
text = text.replace(symbol, '')
build_kgram_model)这是整个 Task 1 最关键的逻辑部分,细分为以下四个步骤:
bool 是 int 的子类(isinstance(True, int) 为 True),因此判断 $k$ 是否为整数时,必须加上 not isinstance(k, bool),否则无法通过单元测试拦截:
if not isinstance(k, int) or isinstance(k, bool):
raise TypeError('k must be an integer')
if k <= 0:
raise ValueError('k must be a positive integer')
',' 和句号 '.' 能够作为独立的 Token 参与建模,在 split 之前调用:
cleaned_text = cleaned_text.replace(',', ' , ').replace('.', ' . ')
这样再按换行和空格切分时,标点便能自然分离开来,与普通单词地位一致。
<END> 标记追加 (Poem Boundaries):
逐行读取切分后的文本。利用 line.isdigit() 识别数字编号行(代表一首新诗的开始)。在遇到新编号或遍历结束时,只要当前 Token 列表中有内容且尾部不是 <END>,就主动追加一个 <END>,精确隔离不同诗篇之间的上下文连贯性。
for i in range(len(tokens) - k):
current_kgram = tuple(tokens[i:i+k])
next_word = tokens[i+k]
if current_kgram not in kgram_model:
kgram_model[current_kgram] = {}
kgram_model[current_kgram][next_word] = kgram_model[current_kgram].get(next_word, 0) + 1
get_next_token_options)查询逻辑极为干净简洁:优先检查输入的 kgram 是否存在于字典 model 中。若存在直接返回对应的下一个 Token 频率字典;若查询不到(未匹配的上下文),则安全返回空字典 {},避免引发 KeyNotFound 报错。
unittest Suite)在测试模块 TestKgramModel 中,我们对整个流程进行了全方位的单元测试覆盖:
test_clean_text_logic:验证大写转小写以及特殊标点保留(如 "HELLO! 'World': sings," $\rightarrow$ "hello world sings,")。test_build_model_basic:测试基础频次累加逻辑(如重复的 "a b c" 能否将 ('a', 'b') 对应的 'c' 频次累加至 2)。test_numbered_poems_and_punctuation:验证数字编号分诗以及 <END> 标记的嵌入位置是否完全准确。test_invalid_inputs:使用 with self.assertRaises(...) 校验传入布尔值 $k$、负数 $k$、非字符串 text 或 Token 长度小于 $k$ 时能否准确引发异常。test_file_errors:结合 tempfile.NamedTemporaryFile 模拟临时空白文件,测试边界异常触发。