Week 7 — Coding Lab / Programming Studio · "Define, Return, Scope"
Course: Introduction to Computer Science — CS1 / Programming Fundamentals in Python (CSCI 1101) · Silver Oak University (fictional sample) · Prof. Okafor
Objective: Objective 5 — define functions with def and parameters; return a value and use it; tell return from print (None); reason about local vs. global scope · SLO A (write & run) + SLO B (trace & debug)
Worth 50 points · Coding Labs group = 15% of the grade · Coding Lab 7
Format: a hands-on programming studio worked in a free online Python environment — you'll (a) write two functions with parameters + return, (b) trace a table of function calls and predict their output (including one that prints None), and (c) find and fix a bug (a missing return / a print where you meant return) — and then catch the AI's mistake when it claims a no-return function "returns" what it printed.
This is the course's signature weekly component. Every instructional week has one Coding Lab. Everything runs in your browser — nothing to buy or install. The whole habit of this lab (and this course): don't guess what a function returns or what a call prints — run it and read what Python actually does.
Midterm heads-up: functions are the last topic on the Week 8 Midterm (cumulative, Weeks 1–7). This lab is exactly the kind of work the midterm rewards.
Part 1 — The Big Picture
For six weeks you wrote code as one long script. This week you learn the biggest organizing tool in the course: the function — a named block you define once with def and call as many times as you want. This lab is the loop, three times: you'll write functions, trace calls (predict what each prints and returns, then run to check), and debug a function whose result mysteriously comes out as None. Along the way you'll watch a function's local variables appear and disappear in Python Tutor — which is what "scope" actually looks like.
Your tools (both free, both in the browser):
- An online Python editor to write and run code: 🔗 https://www.online-python.com/ (or 🔗 https://www.programiz.com/python-programming/online-compiler)
- Python Tutor to watch code run step by step: 🔗 https://pythontutor.com/ — paste a program, click Visualize Execution, then step forward and watch the function's frame pop up and vanish.
Part 2 — Setup (2 minutes)
- Open the online Python editor in a new tab.
- Delete any sample code so you have a blank editor.
- Type and run this — your first function, defined and called:
def square(n):
return n * n
print(square(5))
You should see 25 in the output area. You just defined and called a function. 🎉 (Notice: if you delete the print(square(5)) line and run only the def, nothing prints — defining a function doesn't run it. You have to call it.)
Part 3 — (a) Write: Two Functions with Parameters & Return
Write each of these in the editor, run it, and paste your code and its output into your submission.
square(n)— returns its argument multiplied by itself. Call it and print the result forsquare(5). (It must return the value, not print it.)greet(name)— returns a greeting string like"Hello, " + name. Call it and printgreet("Devon"). (Again: return the string; let the outerprintshow it.)
Check yourself: when you run
print(square(5))andprint(greet("Devon")), you should see25andHello, Devon. If either line printsNone, you printed inside the function instead of returning — fix it so the functionreturns.
Part 4 — (b) Trace: Predict, Then Run
For each program below, first write your predicted output in the table (don't run it yet!) — and for each one predict both what it prints and what value the call returns. Then run each one in the editor and fill in the "Actual" column. Where your prediction and the actual output differ, that's the lesson.
| # | Program | Your prediction | Actual (after running) |
|---|---|---|---|
| 1 | def add(a, b): return a + b print(add(3, 8)) |
______ | ______ |
| 2 | def double(n): return n * 2 print(double(6)) |
______ | ______ |
| 3 | def announce(x): print("Value:", x) print(announce(9)) |
______ | ______ |
| 4 | def avg(a, b): return (a + b) / 2 print(avg(4, 9)) |
______ | ______ |
| 5 | def divide(a, b): return a / b print(divide(20, 4)) |
______ | ______ |
| 6 | x = 10 def bump(): x = 50 bump() print(x) |
______ | ______ |
Hint for #3: there are TWO prints here — the one inside
announce, and the outer one printing the call. What does a function with noreturnhand back?
Hint for #6: look at wherexis assigned. Does assigningxinsidebumpchange thexoutside it?
Visualize one: paste program #6 (the x = 10 / bump() one) into Python Tutor and click Visualize Execution. Step forward and watch: when bump() is called, a new frame for bump appears with its own local x = 50; when bump returns, that frame disappears — and the global x is untouched. That picture is exactly what "local scope" means.
Part 5 — (c) Find & Fix the Bug
Each program below is broken in a way that's classic for functions. For each one: run it, see the surprising result, then write (i) what the result is, (ii) why it happens, and (iii) the fixed program (and what it prints once fixed).
Bug A — the result is None
def area(w, h):
w * h
print(area(3, 5))
Bug B — printed inside instead of returned
def make_total(a, b):
print(a + b)
t = make_total(10, 5)
print("Total is", t)
Part 6 — Analysis Questions
Answer in a sentence or two each:
1. In the trace table, which prediction did you get wrong (if any)? What did you learn from the gap? (Program #3, with its None, is the usual culprit.)
2. Program #3 (announce) printed something and the call returned None. In your own words, what's the difference between what print does and what return does inside a function?
3. Program #6 (bump): the global x stayed 10 even though we set x = 50 inside the function. Why? What does that tell you about a variable created inside a function?
4. For Bug A, the program ran without any error message but the result was None. Why is a None result trickier to catch than a crash with an error message?
5. Connect it: Bug A (forgot return) and Bug B (printed instead of returned) are two different mistakes with the same symptom — a call that hands back None. What single habit catches both?
Part 7 — AI-Critique Moment (required — this is the BYOAI step)
Now bring in your approved chatbot (Gemini, Claude, or ChatGPT) and be the programmer who checks its work.
- Paste this to the chatbot: "What does this Python program print, and what does the call return?
def greet(): print('Hi there!')and thenprint(greet()). Give me the exact output." - Check its claim by running the program yourself in the editor:
- Did it say the program printsHi there!and thenNone? Or did it stop atHi there!and ignore theNone?
- Did it claim the function "returns'Hi there!'" (the thing it printed)? That's the classic AI slip — a function with noreturnreturnsNone, not the printed text. - Write 2–3 sentences reporting what the AI got right and at least one thing you had to correct or verify — most commonly, the AI treating the printed value as the return value, or omitting the
None. If it happened to get everything right, say how you confirmed it by runningprint(greet())and reading both lines — that's the skill.
The habit all term: the tool drafts, you run it and judge. A chatbot will confidently tell you a no-
returnfunction "returns" what it printed — catching that by running the code is the entire point of this course.
Part 8 — What to Submit
Submit a single document (or text entry) with: your Part 3 two functions and their outputs; your completed Part 4 trace table (both columns); your Part 5 bug answers (result, why, and the fix for each); your Part 6 answers; and your Part 7 AI-critique paragraph. Due Sunday, Oct 18, 11:59 p.m. (50 points).
Instructor answer key & model outputs — REMOVE BEFORE PUBLISHING TO STUDENTS
Execution gate: PASS — every output below was produced by actually running the code in Python. Students' Part 3 wording varies; grade those on "does it run and return the right value (not print it)."
Part 3 (model):
1. def square(n): return n * n then print(square(5)) → 25. ✓ (must return, not print inside)
2. def greet(name): return "Hello, " + name then print(greet("Devon")) → Hello, Devon. ✓ (string may vary; must return)
Part 4 trace table (run-verified):
| # | Program | Actual output |
|---|---|---|
| 1 | def add(a, b): return a + b → print(add(3, 8)) |
11 |
| 2 | def double(n): return n * 2 → print(double(6)) |
12 |
| 3 | def announce(x): print("Value:", x) → print(announce(9)) |
Value: 9 then None |
| 4 | def avg(a, b): return (a + b) / 2 → print(avg(4, 9)) |
6.5 |
| 5 | def divide(a, b): return a / b → print(divide(20, 4)) |
5.0 |
| 6 | x = 10 / def bump(): x = 50 / bump() / print(x) |
10 |
(Notes: #3 prints Value: 9 from inside, then the outer print shows the returned None. #4 and #5 are floats because / always returns a float — Week 2 callback. #6 stays 10: the inner x = 50 is a new local that vanishes when bump returns.)
Part 5 bugs (run-verified):
- Bug A def area(w, h): w * h (no return) → print(area(3, 5)) prints None. (i) result is None; (ii) the function computes w * h but never returns it, so the call hands back None; (iii) fix — add return:
python
def area(w, h):
return w * h
print(area(3, 5))
→ 15.
- Bug B def make_total(a, b): print(a + b) → t = make_total(10, 5) / print("Total is", t) prints:
15
Total is None
(i) it prints 15 (the function's own print) then Total is None; (ii) make_total prints the sum but has no return, so it hands back None, and t is None; (iii) fix — return instead of print:
python
def make_total(a, b):
return a + b
t = make_total(10, 5)
print("Total is", t)
→ Total is 15. (Note: now the function prints nothing itself; only the outer line runs, showing Total is 15.)
Part 6 (expected): (1) most commonly #3 (the None) or #6 (global stays 10). (2) print shows a value to a human; return hands a value back to the program so later code can use it — a no-return function returns None. (3) because the inner x = 50 creates a new local variable that exists only inside bump and disappears when it returns; the global x is a different variable, never changed — a variable created inside a function is local. (4) a crash names the problem (an error type + line), but a None result runs silently and "looks fine," so you only catch it by checking what the call actually returns (e.g., printing it) — the bug hides until something downstream misbehaves. (5) the same habit catches both: call the function and print the call (print(f(...))) — read what it actually returns instead of assuming.
Part 7 (AI-critique): full credit for a specific catch — most commonly the AI saying the program "returns 'Hi there!'" or omitting the trailing None. The correct, run-verified output is Hi there! then None. Full credit also if the student verified by running print(greet()) and reporting both lines.
Grading rubric — 50 points
| Criterion | Full | Partial | None |
|---|---|---|---|
Part 3 — wrote 2 functions that return (code + output; both return, not print; calls show 25 and the greeting) (14) |
14 | 7–11 | 0–5 |
Part 4 — trace table (predictions attempted + all 6 actual outputs correct from running, incl. the None and the scope 10) (14) |
14 | 7–11 | 0–5 |
| Part 5 — found & fixed both bugs (result + why + fix for Bug A and Bug B) (12) | 12 | 6–10 | 0–4 |
Part 6 — analysis (return-vs-print, the local-scope 10, why a silent None is tricky) (6) |
6 | 3–5 | 0–2 |
| Part 7 — AI-critique (names a specific thing checked/corrected by running) (4) | 4 | 2 | 0–1 |
Quality gate (self-checked): every model output above (25, Hello, Devon, 11, 12, Value: 9/None, 6.5, 5.0, 10, None, 15, Total is None, Total is 15, Hi there!/None) was produced by actually running the code in Python — execution gate: PASS. No output is hand-traced. The lab grades the student's process (write → run → trace → debug → visualize scope), not a single fixed wording for the open-ended Part 3.
~ Prof. Okafor's edition · Fall 2026 · built with thecoursemaker.com