CP1 / COURSE HOME

Week 11 / Build a checkable report

Use the same function with two sensors

Make the information a calculation depends on visible.

We have a reusable conversion. Reuse becomes unreliable if the function silently uses whichever sensor settings were changed most recently.

Sensor A has offset 0.5 V and sensor B has offset 1.0 V. Both use gain 25 N/V. Each reports 2.5 V.

Start with the problem

Try this first.

Calculate each force on paper. Should processing B first change the result for A? Explain what information each calculation needs.

Why this week's tool?

Parameters pass configuration explicitly. Local variables keep each call’s work separate, so a small library can serve several sensors without hidden changes.

By the end: Process A, then B, then A again and explain why A’s two results agree.

The idea behind the program

Hidden state makes a result harder to reproduce

A function that reads a global offset can change behaviour without changing its visible arguments. To reproduce the result, a reviewer then needs the history of previous cells as well as the current call.

Pass configuration as data

Use a small record with named offset and gain fields. Pass that record to the conversion function. A dictionary makes the dependency visible, but it is still mutable: the team must decide who may modify it.

Compose through clear outputs

A conversion returns a numeric force. A report function can format it. A validation function can return a decision and a reason. Agree on record keys and tuple order so each part knows what the previous part produced.

A short Python example

Read the example alongside the explanation. Run it in a new notebook cell and change one input to see how it behaves.

def convert(voltage_v, calibration):
    return (voltage_v - calibration['offset_v']) * calibration['gain_n_per_v']

sensor_a = {'offset_v': 0.5, 'gain_n_per_v': 25}
sensor_b = {'offset_v': 1.0, 'gain_n_per_v': 25}
print('A:', convert(2.5, sensor_a))
print('B:', convert(2.5, sensor_b))
print('A again:', convert(2.5, sensor_a))

Example output

A: 50.0
B: 37.5
A again: 50.0

Scope locates names; mutation changes objects

A local name can be rebound without rebinding the caller’s name. But if a parameter refers to the caller’s list, mutating that shared object can affect the caller. “Local variable” does not mean “private copy of every object.”

Draw or trace

Draw caller and function frames, each with a name pointing to one list [2, 4]. Compare adding an element to that object with rebinding the local name to a new list.

Predict before running. Which changes the caller’s list: values.append(6), or values = [6] inside the function?

Trace and explanation — after your prediction
  1. append mutates the shared list, so the caller sees [2, 4, 6].
  2. Assignment values = [6] points the local name at a new object.
  3. Without returning and assigning that new object, the caller still refers to its original list.

The first operation changes shared data; the second changes a local binding. Document intended mutation and pass sensor-specific settings as arguments when composing a reusable library.

Change one thing. Use the same helper with two sensor datasets in different orders. Predict which hidden global state could make the result depend on call order.

Türkçe: Kapsam adın nerede bulunduğunu belirler; mutasyon nesneyi değiştirir. Yerel parametre çağıranın nesnesini paylaşabilir.

Examples and variations

Each example changes something about the same problem. Open the ones you want to explore and follow the worked explanation.

01Explicit configuration

2.5 V; A offset 0.5 V; B offset 1.0 V; gain 25 N/V

Question: Predict the results of calls A, B, A.

  1. A: (2.5 − 0.5) × 25 = 50
  2. B: (2.5 − 1.0) × 25 = 37.5
  3. A uses its own unchanged record again

50 N → 37.5 N → 50 N

The call names the calibration it needs. The order does not change the result while records stay unchanged.

02Global-state fault

A global offset changes from 0.5 to 1.0 V between identical convert(2.5) calls

Question: What hidden dependency changes the answer?

  1. First call uses offset 0.5 → 50 N
  2. Another cell rebinds global offset to 1.0
  3. Same visible call now gives 37.5 N

Same argument, different hidden configuration

Reproducibility requires making the calibration and its version visible.

03Shared-record fault

sensor_b = sensor_a; then sensor_b['offset_v'] = 1.0

Question: Has A's configuration changed too?

  1. Both names refer to the same dictionary
  2. Updating B mutates that shared record
  3. A now also reads offset 1.0

A and B both use offset 1.0 V

Explicit arguments help, but they do not prevent aliasing. Create independent records and avoid surprise mutation.

See the Colab code run

Interactive walkthroughs of Scope & Mini-Library. Enable JavaScript to step through code, variables, collections and output. The companion notebook remains available below.

Work on it in Colab

Use the notebook to try the ideas yourself. The steps below connect this week's example to the programming practice.

  1. Run the A–B–A sequence in a fresh runtime and explain why the first and last outputs match.
  2. Build a small faulty version using a global offset. Change the global between calls and record the unexpected difference.
  3. Try the shared-record fault, then construct independent calibration records. Check their values before and after every conversion.
  4. Agree with a partner on the record keys and units. Have them call your function using only that written agreement.

Something to take away: A documented function interface and an A–B–A check showing that one sensor's configuration does not contaminate another's.

Suggested exercises, downloads & solutions

Read the notebook's teaching cells before these exercises.

  • EX01 Scope Prediction (Easy)
  • EX02 Fix the Scope Bug (Easy)
  • EX08 Refactor — Inline to Functions (Medium)
Download notebookWorked solutions

Use the notebook's core and optional labels to choose your workload. This activity fits within guided class time.

Optional notes & guidance
My notes
Using AI or working with a partner

Ask AI to refactor a conversion library. Inspect every global read and every mutation of caller-owned records. Test the call order and verify that a claimed pure conversion does not change its inputs.

You can also review the supplied example with a partner. Use the same inputs to compare the reasoning. Follow the syllabus rules for assessed work.