Subroutines and Scope
What Is a Subroutine?
A subroutine is a named, reusable block of code that performs a specific task. Instead of copying the same code in multiple places, you write it once as a subroutine and call it by name whenever you need it.
OCR J277 requires knowledge of two types of subroutine:
| Type | Returns a value? | Called with | Example use |
|---|---|---|---|
| Function | Yes — produces a result | Used in an expression or assignment | area = calculateArea(5, 3) |
| Procedure | No — performs an action | Called as a standalone statement | displayMenu() |
Benefits of using subroutines:
- Reusability — write once, call many times
- Maintainability — fix a bug in one place, not everywhere
- Readability — a well-named subroutine explains what the code does
- Testing — each subroutine can be tested independently
Procedures perform actions (output, modify state). Functions compute and return a value. A function used without capturing its return value is wasted — you are calling it for the side effect of getting a result but throwing it away.
Functions — Returning Values
A function takes zero or more parameters (input values) and returns exactly one result. The return statement sends the value back to the calling code.
def calculateArea(length, width):
area = length * width
return area
result = calculateArea(5, 3) # result = 15
print(result) # 15
Worked example — function to convert Celsius to Fahrenheit:
def celsiusToFahrenheit(celsius):
fahrenheit = (celsius * 9 / 5) + 32
return fahrenheit
temp_c = 100
temp_f = celsiusToFahrenheit(temp_c)
print(temp_c, "°C =", temp_f, "°F") # 100 °C = 212.0 °F
Verify: (100×9/5)+32=180+32=212 ✓
A function can be called multiple times with different arguments:
print(celsiusToFahrenheit(0)) # 32.0
print(celsiusToFahrenheit(37)) # 98.6
Procedures — Performing Actions
A procedure performs a task but does not return a value. It may display output, update a variable, write to a file, or modify a list.
def displayGreeting(name):
print("Hello,", name)
print("Welcome to the system.")
displayGreeting("Alice")
displayGreeting("Bob")
Worked example — procedure that prints a formatted score report:
def printReport(subject, score):
if score >= 70:
grade = "A"
elif score >= 50:
grade = "B"
else:
grade = "C"
print(subject + ": " + str(score) + "% — Grade " + grade)
printReport("Maths", 82) # Maths: 82% — Grade A
printReport("English", 55) # English: 55% — Grade B
printReport("Science", 44) # Science: 44% — Grade C
Use a procedure when the subroutine's job is to do something (output, modify). Use a function when the subroutine's job is to compute something and hand the result back.
Parameters, Arguments and Passing Arrays
Parameters are the variable names listed in a subroutine's definition. Arguments are the actual values passed in when the subroutine is called.
def add(a, b): # a and b are PARAMETERS
return a + b
result = add(3, 7) # 3 and 7 are ARGUMENTS
Passing an array to a subroutine:
def findMax(numbers):
maximum = numbers[0]
for i in range(1, len(numbers)):
if numbers[i] > maximum:
maximum = numbers[i]
return maximum
scores = [72, 85, 91, 60, 78]
print(findMax(scores)) # 91
Verify: start maximum=72; 85>72→max=85; 91>85→max=91; 60<91→no change; 78<91→no change. Returns 91 ✓
Returning an array from a function:
def doubleAll(numbers):
result = [0] * len(numbers)
for i in range(len(numbers)):
result[i] = numbers[i] * 2
return result
doubled = doubleAll([1, 2, 3, 4]) # [2, 4, 6, 8]
How much of this have you taken in?
Quiz yourself on this section — free, no card needed.
Local and Global Variables
Scope defines which parts of a program can access a variable.
Local variable — declared inside a subroutine. Only accessible within that subroutine. Destroyed when the subroutine ends.
Global variable — declared outside all subroutines. Accessible from anywhere in the program.
A constant is a named value that is assigned once and never changed during the program's execution. Like variables, constants can be local (inside a subroutine) or global (outside all subroutines).
MAX_SCORE = 100 # global constant — accessible everywhere
def grade(score):
PASS_MARK = 50 # local constant — only accessible inside grade()
if score >= PASS_MARK:
return "Pass"
return "Fail"
print(grade(72)) # Pass
print(grade(43)) # Fail
# print(PASS_MARK) # NameError — PASS_MARK is local to grade()
total = 0 # global variable
def addToTotal(amount):
result = amount * 2 # local variable — only exists inside addToTotal
return result
print(total) # 0 — accessible globally
# print(result) # NameError — result does not exist outside addToTotal
Worked example — local vs global:
score = 100 # global
def bonus():
extra = 50 # local to bonus()
return score + extra # can read global score, returns 150
print(bonus()) # 150
print(score) # 100 — unchanged
# print(extra) # NameError — extra is local to bonus()
Using local variables and constants is preferred because they cannot accidentally interfere with the rest of the program. Global variables and constants should be used sparingly — they make programs harder to debug.
Random Number Generation
Programs sometimes need unpredictable values — game dice rolls, random quiz questions, shuffled card decks. OCR J277 requires the ability to create and use random numbers.
import random
dice = random.randint(1, 6) # integer between 1 and 6 inclusive
print(dice)
random.randint(a, b) returns a random integer n where a≤n≤b. Both bounds are inclusive.
Worked example — simulate 5 dice rolls and count sixes:
import random
sixes = 0
for i in range(5):
roll = random.randint(1, 6)
print("Roll:", roll)
if roll == 6:
sixes = sixes + 1
print("Sixes rolled:", sixes)
Worked example — generate a random PIN of 4 digits:
import random
pin = ""
for i in range(4):
pin = pin + str(random.randint(0, 9))
print("PIN:", pin) # e.g. "3807"
Common Exam Mistakes
1. Confusing functions and procedures
A function returns a value — its result is used in an expression or assigned to a variable. A procedure performs an action and returns nothing. If a subroutine outputs something to the screen, that does not make it a function — returning a value does.
2. Treating local variables as accessible globally
A variable declared inside a subroutine cannot be read or modified from outside it. If you need a value from inside a subroutine, return it (function) or pass the outer variable as a parameter.
3. Confusing parameters and arguments
Parameters are the names in the definition: def add(a, b). Arguments are the values at the call site: add(3, 7). Exam questions may ask which is which.
4. Off-by-one with randint
random.randint(1, 6) can return 1, 2, 3, 4, 5, or 6 — both bounds are included. random.randint(0, 9) gives digits 0–9 inclusive, which is 10 possible values.
| Mistake | Correction |
|---|---|
Saying displayMenu() is a function because it "does stuff" | It returns no value — it is a procedure |
| Accessing a local variable outside its subroutine | Return the value from the subroutine or pass it as a parameter |
random.randint(1, 5) to roll a standard die | Use random.randint(1, 6) — a standard die has faces 1–6 |
Generate revision on any topic you study
Type any topic you're studying and Aicademy generates a complete lesson, quiz, and flashcard set — personalised to your level.
Lessons on anything
Structured, level-matched lessons on any topic you study
Practice quizzes
Find out what you actually know before the exam does
Flashcard sets
Lock in key concepts with instant revision cards
Ask Aica
Stuck on something? Get a clear explanation, any time
SQL Basics
Defensive Design
Related lessons
7 Slides
7 Slides
7 Slides
7 Slides