1.2.4 - Programming paradigms and procedural code
A programming paradigm offers a way to organise a solution. You will compare the reasons for different approaches, then build procedural programs using values, expressions, input, strings and subroutines with explicit data flow.
Different paradigms organise different kinds of problem
A programming paradigm is an approach to structuring computation. Languages can support several paradigms, so choosing Python does not force every program into one style. The approach should help represent the problem and make the solution understandable and maintainable.
Procedural programming organises a solution as a sequence of commands, with selection, iteration and named subroutines. A small utility that reads measurements, calculates a result and writes a report maps naturally to these steps. Reusing calculation functions avoids repeated logic. As shared mutable state and many interdependent procedures accumulate, understanding changes can become harder unless interfaces are clear.
Object-oriented programming groups state and behaviour into objects. A simulation with many vehicles can benefit from each vehicle having its own data and operations, and related vehicle types sharing structure. This brings design overhead that may be unnecessary for a tiny one-off calculation. The detailed object-oriented mechanisms are developed in a separate lesson.
In a declarative approach, a program states a required result or relationship rather than explicitly controlling every step. SQL describes which records are wanted; the database chooses an execution plan. Functional approaches build results by composing functions and emphasising expressions, often avoiding mutable state. Low-level assembly programming exposes machine operations and is useful when close control of hardware or an instruction sequence is required, at the cost of architecture dependence and more detail to manage.
These approaches address different needs rather than form a ranking. A program can use procedural code to coordinate work, SQL to retrieve data and objects to represent domain entities. A paradigm does not guarantee speed, security or correctness: its usefulness depends on the task and implementation.
Variables and expressions represent changing values
A variable names a value that may change. A constant represents a value intended to remain fixed. Python uses an uppercase naming convention such as MINUTES_PER_HOUR, but it does not prevent reassignment; some languages provide enforced constant declarations.
MINUTES_PER_HOUR = 60
hours = 2
minutes = hours * MINUTES_PER_HOUR
hours = 3
print(minutes)
Stored-result example
Example run120
The minutes assignment stores the result 120, rather than a formula that automatically follows hours. Integer, floating-point, Boolean and string values serve different purposes: a quantity, a measured value, a true/false condition and text. A digit string such as "12" is not the integer 12; adding strings concatenates them, while adding integers performs arithmetic.
An expression combines values and operators to produce a value. Python uses +, -, *, /, //, % and ** for addition, subtraction, multiplication, division, integer floor division, remainder and powers. For non-negative integers, 17 // 5 is 3 and 17 % 5 is 2. OCR pseudocode uses DIV, MOD and ^ for the corresponding positive-integer examples; Python ^ is not a power operator. Use parentheses to express intended grouping: 2 + 3 * 4 is 14, while (2 + 3) * 4 is 20.
Comparisons use ==, !=, <, <=, > and >=. Python's and, or and not correspond to OCR's AND, OR and NOT. For age >= 18 and not suspended, both sufficient age and absence of suspension are required. Assignment = changes a binding; comparison == tests equality.
Input must be converted before numeric calculation
Python's input(prompt) returns a string, even when the user types digits. Casting converts a value to a requested type when that conversion is valid. int("7") gives integer 7, float("2.5") gives floating-point 2.5 and str(7) gives text "7".
packs = int(input("Packs: "))
price = float(input("Price per pack: "))
total = packs * price
print("Total: " + str(total))
Pack-price example
Example runPacks: 3
Price per pack: 2.5
Total: 7.5
This example assumes a non-negative whole-number pack count and a valid non-negative price. Without the integer cast, "3" * 2 repeats the text to make "33"; it does not calculate six packs. Invalid text such as "three" cannot be converted by int, so input conversion can fail. Type conversion and validation are different: int("-2") succeeds, but a negative number still violates this pack-count requirement. A robust version must check the range and decide how to report or retry invalid entries.
For ordinary monetary software, choose a representation and rounding policy deliberately rather than assume binary floating point stores every decimal price exactly. Here the example illustrates casting and data flow, not a complete financial application. Separating input from calculation also lets a calculation be tested without repeatedly arranging keyboard input.
String handling extracts and builds useful text
String processing uses positions and lengths to turn input text into useful results. Python uses zero-based positions and len(text) for the number of characters. A slice text[start:end] includes start and excludes end. OCR pseudocode instead uses text.subString(start, count), so translation must convert a count into an end position.
reference = "CAB-204"
prefix = reference[0:3]
number_text = reference[4:7]
number = int(number_text)
print(prefix + ": " + str(number + 1))
Reference example
Example runCAB: 205
The reference has seven characters. The prefix uses positions 0,1,2; the numeric text uses 4,5,6. The hyphen at position 3 is skipped deliberately. The equivalent OCR substrings are .subString(0, 3) and .subString(4, 3). Casting turns "204" into a number before addition. Concatenating number_text + "1" would instead produce "2041".
Check the format before relying on fixed positions: a short reference or a non-digit suffix cannot satisfy this routine's assumptions. For a fixed-width code, preserving leading zeros may be essential, so decide whether a component is an identifier string or a number before casting it. A slice does not alter the original string.
Subroutines separate calculation from interaction
Subroutines and their results
A subroutine is a named section of code that can be called. A function returns a value for its caller to use; a procedure performs an action without supplying such a result.
A parameter is the name in the definition, and an argument is the value supplied at a call.
The following calculation accepts non-negative numeric hours and returns the equivalent minutes. The display procedure then receives that number and writes a labelled message.
function minutes(hours)
result = hours * 60
return result
endfunction
procedure show_minutes(amount)
print("Minutes: " + str(amount))
endprocedure
answer = minutes(2)
show_minutes(answer)
This prints Minutes: 120. The function receives 2, calculates and returns 120; the procedure displays the argument supplied to it. result is local to the function. Each call has its own local state. In OCR pseudocode, passing is assumed by value unless stated otherwise: changing a value parameter does not reassign the caller's variable. Explicit byVal and byRef identify value and reference passing when relevant. With byRef, an update through the parameter can change the caller's variable. Detailed parameter tracing is taught separately.
Python uses def for both styles; a routine with no value return gives None. This procedural version makes its contract visible:
def minutes(hours):
return hours * 60
def show_minutes(amount):
print("Minutes: " + str(amount))
answer = minutes(2)
show_minutes(answer)
Printing in minutes instead of returning would display a value but would not provide the numeric result needed by a caller that adds it to another duration. Inputs as parameters and results as return values reduce dependence on global mutable state. In OCR, global explicitly gives a main-program variable global scope; using many routines that change the same global value can hide the order on which a result depends.
Reusable functions can be tested directly: minutes(0) → 0, minutes(1.5) → 90.0 and minutes(2) → 120, under a contract allowing non-negative numeric hours. A file-processing program can similarly separate reading, calculation and writing, though actual file operations need the file-handling lesson's contracts. A console routine does not supply the GUI required for an assessed H446 project. These examples practise programming; they do not complete a candidate's independent project.
Try the two calls below before changing the calculation. Predict each returned value and the combined total, then run the sandbox. Change the first argument to 0 and the second to 2: the caller should receive 0 and 120 and combine them into 120. To investigate the distinction, replace the function's return hours * 60 with print(hours * 60) and run again. The function displays its calculations, but its calls return None; adding those results fails. Restore return to repair the data flow. Keep arguments non-negative numeric hours.
Combine returned durations
{"code":"def hours_to_minutes(hours):\n return hours * 60\n\nfirst = hours_to_minutes(1.5)\nsecond = hours_to_minutes(0.5)\ncombined = first + second\nprint("First: " + str(first))\nprint("Second: " + str(second))\nprint("Combined: " + str(combined))","instructions":"Predict the two returned values and their combined total, then Run. Change the call arguments to 0 and 2 and run again. Finally investigate printing inside the function instead of returning, then restore the return statement. This is ungraded practice.","exercise_id":"h446-1.2.4-returned-durations-sandbox","task_version":"1","runtime_profile":"python-console-v1","original_filename":"durations.py","file_mode":"fresh","files":[]}
The original calls return 90.0 and 30.0, so the caller displays a combined 120.0. In the print-only version, the displayed calculations are side effects: the caller receives two None values and the addition raises a TypeError before the three labelled lines can print.
Return supplies data to the caller
A returned value can become an operand in the caller's next calculation. Printing displays information; it does not supply that number as the call's result.
Standalone Python source tasks use the preserved editor; runnable tasks may execute supported console code. Run checks behaviour and does not submit or grade an answer. OCR pseudocode source tasks use a no-run editor with a truthful language label.