Practice Questions · AP CSP-Feeder · US / ON / BC / AB Styles练习题集 · AP CSP 衔接 · 美 / 安 / 卑 / 阿省风格
3A-AP-17 · 3A-AP-18 · AAP-3.BICS3U A3.1 · A3.2 · B2.3Full Syllabus Map in Study Guide: ../Study Guides/Unit_4_Functions_and_Modular_Design.html. CS has no AB standalone diploma exam; AB framing uses CSE2110 outcomes.完整大纲对照见学习指南:../Study Guides/Unit_4_Functions_and_Modular_Design.html。CS 无独立 AB 毕业考;AB 题使用 CSE2110 结果框架。
Full solutions below. For MCQs, the correct letter is identified with justification. For short-answer items, complete worked solutions are provided. Code traces show each variable at each step.以下为完整解答。选择题标明正确字母并附说明。短答题提供完整解题过程。代码追踪显示每一步每个变量的值。
Elimination: (A) is false: repeated code does not slow execution meaningfully. (C) is false: Python has no such restriction. (D) is minor and not the main issue. The correct answer is (B): maintainability. Duplicated code creates N places to fix instead of 1. CSTA 3A-AP-18: "Create artifacts by using procedures within a program." M1 (reasoning) + A1 (correct letter)排除法:(A) 错误:重复代码对执行速度影响微乎其微。(C) 错误:Python 无此限制。(D) 是次要问题,非主要缺点。正确答案是 (B):可维护性。重复代码意味着要修复 N 处而非 1 处。CSTA 3A-AP-18:"通过在程序中使用过程来创建制品。" M1(推理)+ A1(正确字母)
Hello, Sam! then Hello, Alex! A1(C) Hello, Sam! 然后 Hello, Alex! A1The function IS called twice (eliminating A). Arguments bind in order: first call binds name = "Sam" printing Hello, Sam!; second call binds name = "Alex" printing Hello, Alex!. (B) is wrong because name is the parameter placeholder; it receives the actual argument. (D) reverses the order. M1 (reasoning) + A1 (correct letter)该函数确实被调用了两次(排除 A)。实参按顺序绑定:第一次调用绑定 name = "Sam",打印 Hello, Sam!;第二次调用绑定 name = "Alex",打印 Hello, Alex!。(B) 错误,因为 name 是形参占位符,它接收实际实参。(D) 颠倒了顺序。M1(推理)+ A1(正确字母)
def block executes only when the function is called. Each call creates a fresh binding of the argument to the parameter name, so the same function can produce different output each time it is called with different arguments.定义函数不会运行它。def 块内的代码只在函数被调用时执行。每次调用都会将实参新鲜地绑定到形参名,因此同一函数每次用不同实参调用时可以产生不同的输出。base and exponent. [1]形参:base 和 exponent。[1]power(3, 2): base = 3, exponent = 2. Loop runs twice (i = 1, 2). After i=1: result = 1*3 = 3. After i=2: result = 3*3 = 9. Return value = 9. M1 (bindings) + M1 (trace) + A1 (return value) = [3]调用 power(3, 2):base = 3,exponent = 2。循环执行两次(i = 1, 2)。i=1 后:result = 1*3 = 3。i=2 后:result = 3*3 = 9。返回值 = 9。M1(绑定)+ M1(追踪)+ A1(返回值)= [3]power(2, 4) = 16; the function multiplies 2 by itself 4 times (2^4 = 16). [1]power(2, 4) = 16;该函数将 2 自乘 4 次(2^4 = 16)。[1]base, exponent) are placeholders in the definition. Arguments (3, 2) are the actual values supplied at the call site. Each call produces fresh, independent copies of the parameters. That is why calling power twice with different arguments gives different results without either call affecting the other.形参(base、exponent)是定义中的占位符。实参(3、2)是调用处提供的实际值。每次调用都会产生形参的全新独立副本,这就是为什么用不同实参两次调用 power 会给出不同结果,而两次调用互不影响。grade(82), so score = 82. Check: 82 >= 90? No. 82 >= 80? Yes. RETURN "B" executes immediately. Return value = "B". M1 (trace IF sequence) + M1 (identify correct RETURN) + A1 (value) = [3]调用 grade(82),score = 82。检查:82 >= 90?否。82 >= 80?是。立即执行 RETURN "B"。返回值 = "B"。M1(追踪 IF 序列)+ M1(确定正确的 RETURN)+ A1(值)= [3]result, then output). Output 2: F (55 < 60, falls through to last RETURN). [2]输出 1:B(存入 result 后输出)。输出 2:F(55 < 60,落到最后的 RETURN)。[2]score = 50 has been set before Line A; the function has not yet been called so it has not been modified. A1 + M1 = [2]第 A 行:50。全局变量 score = 50 已在第 A 行之前设置;函数尚未被调用,因此未被修改。A1 + M1 = [2]update(score) returning the new value) makes the function's behaviour depend only on its inputs, not on hidden state. One risk of global state: calling the function twice gives different results each time because the global accumulates changes, breaking reproducibility. M1 + A1 = [2]使用基于参数的设计(update(score) 返回新值)使函数的行为只取决于其输入,而不取决于隐藏状态。全局状态的一个风险:多次调用函数每次给出不同结果,因为全局变量累积变化,破坏了可重现性。M1 + A1 = [2]Worked solutions below. All traces show variable values at each step. Mark scheme notes are shown in JetBrains Mono. Each solution card ends with an Insight block identifying the key examiner expectation.以下为解题过程。所有追踪均显示每一步的变量值。评分要点以等宽字体标注。每张解答卡以解题思路模块结束,指出考查的核心要点。
get_scores returns a list, so it IS value-returning. Correction: the two procedures are display_report only has OUTPUT, no RETURN. get_scores has a RETURN. Re-check: get_scores RETURN scores = value-returning. compute_average RETURN = value-returning. letter_grade RETURN = value-returning. display_report = outputs only, no RETURN = procedure. So only display_report is a pure procedure. Accept: display_report (no RETURN); note get_scores also returns. A1 (display_report) + M1 (justification = has OUTPUT but no RETURN) = [2]过程(无返回值):重新检查:get_scores 返回成绩列表(有 RETURN)= 有返回值。compute_average 有 RETURN = 有返回值。letter_grade 有 RETURN = 有返回值。display_report 只有 OUTPUT,无 RETURN = 过程。因此只有 display_report 是纯过程。可接受:display_report(无 RETURN);注意 get_scores 也有返回值。 A1(display_report)+ M1(理由 = 只有 OUTPUT 无 RETURN)= [2]compute_average with known values before connecting it to the rest. (ii) If the average formula needs to change, only compute_average needs editing, not the entire program. (iii) The main program reads like a high-level story, hiding complexity in sub-functions. M1 + A1 = [2]接受以下任意一个:(i) 每个函数可以独立测试;例如,在与其余部分连接之前,用已知值测试 compute_average。(ii) 如果平均值公式需要更改,只需编辑 compute_average,而不是整个程序。(iii) 主程序读起来像高层故事,将复杂性隐藏在子函数中。M1 + A1 = [2]letter_grade) can be reused in other programs.模块化设计让每个函数只做一件明确的事(单一职责)。主程序变成了一个可读的高层操作列表:获取、计算、分类、显示。这种自顶向下的结构意味着你可以独立测试、调试和修改每一层,并且相同的子函数(如 letter_grade)可以在其他程序中复用。add_and_double(3, 7): a = 3, b = 7. Inside: total = 3 + 7 = 10. Then calls double(10): n = 10, returns 10 * 2 = 20. add_and_double returns 20. M1 (bindings) + M1 (total) + A1 (20) = [3]调用 add_and_double(3, 7):a = 3,b = 7。内部:total = 3 + 7 = 10。然后调用 double(10):n = 10,返回 10 * 2 = 20。add_and_double 返回 20。M1(绑定)+ M1(total)+ A1(20)= [3]add_and_double(5, 5) = double(10) = 20. [2]打印 1:20(x = 20)。打印 2:add_and_double(5, 5) = double(10) = 20。[2]double is reused inside add_and_double without duplicating the multiplication logic. [1]函数可以调用另一个函数,因此 double 在 add_and_double 内部被复用,无需重复乘法逻辑。[1]double multiplying by 3: add_and_double(3, 7) = double(10) = 30. add_and_double(5, 5) = double(10) = 30. New outputs: 30 and 30. [2]double 改为乘以 3 后:add_and_double(3, 7) = double(10) = 30。add_and_double(5, 5) = double(10) = 30。新输出:30 和 30。[2]double's logic lives in one place, changing it once (multiply by 3) automatically updates every caller. If the multiplication had been written inline in both functions, you would need to change it in two places.(d) 部分正是 DRY 原则的实际体现:因为 double 的逻辑只存在于一处,修改一次(乘以 3)会自动更新所有调用方。如果乘法被内联写在两个函数中,就需要在两处进行修改。n = 4. result = 4 * 4 = 16. Return value = 16. M1 + A1 = [2]n = 4。result = 4 * 4 = 16。返回值 = 16。M1 + A1 = [2]result is a separate storage location scoped to that function; they are created independently each time the function is called and destroyed when it returns. [1]每个函数的局部变量 result 是作用于该函数的独立存储位置;每次调用函数时独立创建,函数返回时销毁。[1]result = 0 # global
def square(n):
global result
result = n * n
return result
This is worse because: if cube also used global result, calling one function would overwrite the value the other stored, causing unpredictable results when the functions are called in sequence. A1 (code) + A1 (reason) = [2]全局版本的 square:result = 0 # global
def square(n):
global result
result = n * n
return result
这样更差,因为:如果 cube 也使用 global result,调用一个函数会覆盖另一个函数存储的值,当函数按序调用时会导致不可预期的结果。A1(代码)+ A1(原因)= [2]result as a variable name without conflict. This is one of the core benefits of functions: they create isolated namespaces. Global variables break this isolation, which is why CSE2110 outcome 3.3 specifically asks students to "analyze and determine the type of scope required."局部作用域使得两个函数都能使用 result 作为变量名而不冲突。这是函数的核心优势之一:它们创建了隔离的命名空间。全局变量破坏了这种隔离,这就是为什么 CSE2110 结果 3.3 特别要求学生"分析并确定所需的作用域类型"。add_item(10) after the two existing calls adds to the already-accumulated total = 45, giving 55, not 10. The result depends on hidden state (the current value of the global) which is not visible at the call site, making behaviour hard to predict. M1 + A1 = [2]在两次现有调用之后调用 add_item(10),会在已累积的 total = 45 基础上累加,得到 55,而非 10。结果依赖于隐藏状态(全局变量的当前值),这在调用处不可见,使行为难以预测。M1 + A1 = [2]add_item does not depend on any external state; all it needs is its two parameters. It also has high cohesion: the function has one clear job (add a price to a running total) with no side effects. Low coupling + high cohesion is the goal of modular design (AB CSE2110 outcome 3.4). M1 + A1 = [2]程序 B 的耦合度低:add_item 不依赖任何外部状态,只需要两个形参。它也有高内聚度:函数只做一件明确的事(将价格加到累计总额),没有副作用。低耦合 + 高内聚是模块化设计的目标(AB CSE2110 结果 3.4)。M1 + A1 = [2]LANGUAGE = "EN") used across many functions is appropriate as a global constant because it is set once at startup and never changes during execution. [1]可接受例如:程序范围的语言偏好(LANGUAGE = "EN")在许多函数中使用,作为全局常量是合适的,因为它在启动时设置一次,在执行期间从不改变。[1]add_item is a pure function; Program A's is not: it is coupled to global state and produces side effects.耦合度衡量函数对外部事物的依赖程度。内聚度衡量函数职责的专注程度。理想的函数是一个黑盒:给定相同的输入,无论程序其余部分如何,它始终返回相同的输出。程序 B 的 add_item 是一个纯函数;程序 A 的不是:它与全局状态耦合并产生副作用。Full worked solutions below. All function designs show both pseudocode and Python where applicable. Traces list all parameter bindings and return values explicitly.以下为完整解答。所有函数设计在适用时同时展示伪代码和 Python。追踪过程明确列出所有形参绑定和返回值。
FUNCTION to_fahrenheit(celsius):
SET fahrenheit TO celsius * 9 / 5 + 32
RETURN fahrenheit
END FUNCTION
Award marks for: FUNCTION keyword + parameter name [M1]; correct formula [M1]; RETURN statement [A1]. [3]伪代码:FUNCTION to_fahrenheit(celsius):
SET fahrenheit TO celsius * 9 / 5 + 32
RETURN fahrenheit
END FUNCTION
评分要点:FUNCTION 关键字 + 形参名 [M1];正确公式 [M1];RETURN 语句 [A1]。[3]to_fahrenheit(0): celsius=0, fahrenheit = 0*9/5+32 = 32.0. to_fahrenheit(100): celsius=100, fahrenheit = 100*9/5+32 = 180+32 = 212.0. A1 + A1 = [2]to_fahrenheit(0):celsius=0,fahrenheit = 0*9/5+32 = 32.0。to_fahrenheit(100):celsius=100,fahrenheit = 100*9/5+32 = 180+32 = 212.0。A1 + A1 = [2]def to_fahrenheit(celsius):
fahrenheit = celsius * 9 / 5 + 32
return fahrenheit
A1 (def + parameter) + A1 (formula + return) = [2]Python:def to_fahrenheit(celsius):
fahrenheit = celsius * 9 / 5 + 32
return fahrenheit
A1(def + 形参)+ A1(公式 + return)= [2]Min: 65Max: 91Avg: 78.8Min: 65Max: 91Avg: 78.8def find_range(data):
return find_max(data) - find_min(data)
A1 (calls find_max/find_min) + A1 (subtraction, return) = [2]Python:def find_range(data):
return find_max(data) - find_min(data)
A1(调用 find_max/find_min)+ A1(减法,return)= [2]find_range(scores) = find_max([72,88,65,91,78]) - find_min([72,88,65,91,78]) = 91 - 65 = 26. [1]find_range(scores) = find_max([72,88,65,91,78]) - find_min([72,88,65,91,78]) = 91 - 65 = 26。[1]find_range is built on top of find_max and find_min, which are themselves built on top of built-in functions. This layering is the essence of modular design. BC CP11 calls it "pre-built libraries and their documentation": you use existing, tested building blocks rather than starting from scratch every time.(c) 部分展示了函数组合:find_range 构建在 find_max 和 find_min 之上,而后者本身又构建在内置函数之上。这种分层正是模块化设计的本质。BC CP11 将其称为"预建库及其文档":你使用现有的、经过测试的构建块,而不是每次从头开始。FUNCTION apply_discount(total, discount_pct):
SET discount TO total * discount_pct / 100
RETURN total - discount
END FUNCTION
With discount_pct=10: apply_discount(138.0, 10) = 138.0 - 13.8 = 124.2. New share = per_person(124.2, 4) = 31.05. A1 (function) + M1 (124.2) + A1 (31.05) = [3]伪代码:FUNCTION apply_discount(total, discount_pct):
SET discount TO total * discount_pct / 100
RETURN total - discount
END FUNCTION
discount_pct=10 时:apply_discount(138.0, 10) = 138.0 - 13.8 = 124.2。新人均分摊 = per_person(124.2, 4) = 31.05。A1(函数)+ M1(124.2)+ A1(31.05)= [3]