Home / GCSE · Edexcel / Computer Science / Problem solving with programming

CPX20Subprograms, Scope and Library Modules

Edexcel 1CP2 · 6.6.1

Subprograms you don't write: built-in and library

Pearson's definition: a subprogram is a distinct, named block of code, with its own scope, that performs a specific task and is called from other code.

  • Pre-existing subprograms were written by someone else. You just call them by name.
  • Built-in subprograms are always there, with no import: print, input, len, int, float, str, bool, round, range, ord and chr.
  • Library modules are collections of subprograms that must be imported first. The PLS uses four: random, math, time and turtle.
  • Import at the top of the file, under the # Import libraries banner. Then put the library name, a dot and the subprogram: random.randint (1, 6), math.sqrt (49).
  • String and list subprograms are pre-existing too. They are called on a value: name.upper (), scores.append (7).
  • User-devised subprograms are the ones you write yourself with def: procedures and functions.
  • Built-in and library subprograms in action:
    # -------------------------------------------------------------------
    # Import libraries
    # -------------------------------------------------------------------
    import math
    
    # -------------------------------------------------------------------
    # Main program
    # -------------------------------------------------------------------
    area = float (input ("Area of the square lawn in square metres: "))
    side = math.sqrt (area)                       # library subprogram
    print ("Each side is", round (side, 2), "m")  # built-in subprograms
  • With an input of 20, this displays Each side is 4.47 m.
Exam tipIf Python says NameError: name 'math' is not defined, the import line is missing. Paper 2 starting files often say “Add a line to import the … library”: that's a mark for one line, import math, in the right section.
Subprogram
A distinct, named block of code, with its own scope, that performs a specific task and is called from other code.
Built-in subprogram
A subprogram that is part of Python and can be called without importing anything, such as len () or print ().
Library module
A collection of pre-written subprograms that must be imported before use, such as random or math.
User-devised subprogram
A procedure or function written by the programmer.
Edexcel 1CP2 · 6.6.1, 6.6.2

Writing procedures

A procedure is a subprogram that does not return a value. It may or may not take parameters.

  • Define it with def, a name, brackets and a colon. The body is indented. Pearson leaves a space before the brackets: def showMenu ():.
  • Defining a procedure doesn't run it. It runs only when it is called by name: showMenu ().
  • When it is called, the program jumps to the procedure, runs its body, then carries on from the line after the call.
  • A procedure with no parameters and one with a parameter:
    def showMenu ():
        print ("1  Add a score")
        print ("2  Show scores")
        print ("3  Quit")
    
    def drawLine (pLength):
        print ("-" * pLength)
    
    drawLine (16)
    showMenu ()
    drawLine (16)
  • This displays a line of 16 dashes, the three menu lines, then another 16 dashes.
  • A procedure gives nothing back, so call it on a line of its own.
  • Put every definition under the # Subprograms banner, before the main program. Never write a def inside the main program's loops or if blocks.

A call jumps to the subprogram; when it ends, the program carries on after the call. A function also sends a value back.

Exam tip“Add a procedure, with no parameters, to display a welcome message” has two parts: the definition in the Subprograms section and a call in the right place in the main program. Each usually earns a mark.
Procedure
A subprogram that may or may not take parameters but does not return a value to the calling code.
Call
Running a subprogram by writing its name, with any arguments in brackets.
Edexcel 1CP2 · 6.6.1, 6.6.2

Writing functions and returning values

A function always returns a value to the calling code. It may or may not take parameters.

  • return (value) sends a value back. The PLS writes it with brackets: return (total).
  • Call a function as part of an expression, so the value is used: store it, display it, or test it.
    def withVat (pPrice):
        newPrice = pPrice * 1.2
        return (newPrice)
    
    cost = withVat (15.0)          # stored: cost is 18.0
    print (withVat (2.5))          # displayed: 3.0
    if (withVat (cost) > 20):      # tested: 21.6 is over 20
        print ("Over the limit")
  • Return isn't the same as print. print shows a value to the user, but the calling code can't use it. return hands the value to the calling code and shows nothing.
  • If a function prints instead of returning, the calling code gets None.
  • return ends the subprogram at once. Pearson's style is one exit: keep the result in a local variable and return it on the last line.
  • A function with no parameters often gets input: def getChoice (): asks the user and returns the choice.
  • To send back more than one value, return a list: return ([lowest, highest]), then index the list that comes back.
ProcedureFunction
Returns a value?NoYes, always
Parameters?OptionalOptional
How it's calledshowResult (score) on its own linetotal = addUp (scores), inside an expression
Typical jobsDisplay, draw, write to a fileCalculate, check (True/False), get a value
Worked exampleWrite a function lowHigh that takes a list of numbers and returns the lowest and highest as a list.
  1. Start both at the first item, then compare every item with them.
    def lowHigh (pValues):
        lowest = pValues[0]
        highest = pValues[0]
        for value in pValues:
            if (value < lowest):
                lowest = value
            elif (value > highest):
                highest = value
        return ([lowest, highest])
    
    result = lowHigh ([14, 3, 27, 9])
    print ("Lowest", result[0], "highest", result[1])
  2. One loop, one return at the end. The calling code stores the list and indexes it.
Displays Lowest 3 highest 27.
Exam tipWhen a question says a subprogram “returns” something, the mark needs return. A print inside the function scores nothing for that mark, and so does calling the function on its own line and throwing the value away.
Function
A subprogram that may or may not take parameters but always returns a value to the calling code. It is called as part of an expression.
Return value
The value a function sends back to the code that called it.
Edexcel 1CP2 · 6.6.2

Parameters and arguments

  • Parameters are the variables in brackets on the definition line. Arguments are the values or variables passed in when the subprogram is called.
  • Arguments are matched to parameters by position: the first argument goes into the first parameter, and so on. List them in the same order as the definition.
  • The number must match. One argument short gives a TypeError such as “missing 1 required positional argument”.
  • Parameters are local variables of the subprogram: they exist only while it runs.
  • Pearson's tip: start parameter names with p (pName, pNights) so they can't be confused with variables elsewhere.
  • An argument can be a literal, a variable, an expression or a whole list.
    def showBooking (pName, pNights, pRate):
        cost = pNights * pRate
        print (pName, "owes", cost)
    
    guest = "Ayo"
    nights = 3
    showBooking (guest, nights, 45)       # Ayo owes 135
    showBooking ("Kit", nights + 1, 40)   # Kit owes 160
  • Arguments in the wrong order don't always crash. Sometimes they just give a wrong answer, which is a logic error.
Where it appearsExample
ParameterIn the definition linedef showBooking (pName, pNights, pRate):
ArgumentIn the callshowBooking (guest, nights, 45)
Exam tip“Change the names of the parameters” means changing them on the definition line and everywhere they are used in the body. Examiners reported students who renamed the parameters but left the old names inside, so the subprogram quietly used the global variables instead.
Parameter
A variable named in a subprogram's definition line that receives a value when the subprogram is called. It is local to the subprogram.
Argument
A value or variable passed into a subprogram in the call.
Edexcel 1CP2 · 6.6.3

Local and global variables

The scope of a variable is the part of the program in which it exists and can be used.

  • A global variable is created at the level of the main program (Pearson puts them under # Global variables). It can be used anywhere.
  • A local variable is created inside a subprogram, and that includes its parameters. It exists only while the subprogram runs, then it's gone.
  • The same identifier can mean different things in different scopes. A local total is a different variable from a global total.
    total = 100                  # global
    
    def addBonus (pScore):
        total = pScore + 5       # a new local variable, also called total
        return (total)
    
    print (addBonus (40))        # 45
    print (total)                # 100: the global hasn't changed
  • Using a local variable outside its subprogram gives a NameError, because it no longer exists.
  • Why keep globals to a minimum: names can clash, any line can change a global (so bugs are harder to trace), and a subprogram that depends on globals can't be reused or tested on its own.
  • Good practice: pass data in as arguments and send results out with return. Don't reach out to global variables from inside a subprogram.
  • Constants can be used inside subprograms, because their values never change.
  • The global keyword isn't in the PLS, and Pearson advises against it. If a value is needed everywhere, declare and initialise it at the main program level.

Each subprogram has its own local variables. The two variables called total are different variables.

Exam tipA mark for “the subprogram uses its parameters” is often refused if the global variable's name appears anywhere inside the subprogram, even when the program works.
Scope
The part of a program in which a variable exists and can be used.
Global variable
A variable defined at the level of the main program, accessible from anywhere in the program.
Local variable
A variable defined inside a subprogram (including its parameters). It can only be used inside that subprogram and stops existing when the subprogram finishes.
Edexcel 1CP2 · 6.6.1

The random library

  • random.randint (a, b) returns a random whole number from a to b, including both ends. A dice roll is random.randint (1, 6).
  • A random index into a list: random.randint (0, len (pList) - 1). The last index is one less than the length.
  • random.random () returns a random real number from 0.0 up to, but not including, 1.0.
  • Use random.random () for a percentage chance: if (random.random () < 0.3): is True about 30% of the time.
  • Multiply to change the range: random.random () * 50 is a real from 0 up to 50.
  • Random programs give different output each run. Test by running several times and checking every value is in range, and that the end values (such as 1 and 6) do turn up.
  • Picking a random item by index:
    import random
    
    tips = ["Drink water", "Stretch", "Look away from the screen", "Walk"]
    index = random.randint (0, len (tips) - 1)
    print ("Break tip:", tips[index])
Worked exampleGenerate a random even number from 2 to 20 inclusive.
  1. There are 10 even numbers, 2 × 1 up to 2 × 10.
  2. Pick a whole number from 1 to 10 and double it: evenNum = 2 * random.randint (1, 10).
2 * random.randint (1, 10)
Exam tipWhen a question says “generate a random index”, use random.randint. Pearson refused random.choice (which isn't in the PLS) for that mark. Tie the upper bound to the list with len (…) - 1 rather than typing a number.
random.randint (a, b)
Returns a random integer X so that a ≤ X ≤ b.
random.random ()
Returns a random real number from 0.0 up to (not including) 1.0.
Edexcel 1CP2 · 6.6.1

The math and time libraries

  • Use math.ceil whenever you need whole packs, boxes, buses or trays: 50 cakes in boxes of 12 need math.ceil (50 / 12), which is 5 boxes.
  • round is wrong for packs: round (50 / 12) is 4, leaving 2 cakes with no box.
  • math.floor gives the number of completely full boxes: math.floor (50 / 12) is 4.
  • For negative numbers math.floor and int differ: math.floor (-4.1) is −5, but int (-4.1) is −4.
  • Use math.pi rather than typing 3.14: it's more accurate and easier to read.
  • time.sleep slows a program down for countdowns, animations and simulations. The number of seconds can be a real, such as 1.5.
Subprogram or constantWhat it givesExample → result
math.ceil (x)The smallest integer greater than or equal to x (rounds up)math.ceil (4.1) → 5
math.floor (x)The largest integer less than or equal to x (rounds down)math.floor (4.9) → 4
math.sqrt (x)The square root, as a realmath.sqrt (49) → 7.0
math.piThe constant π (a value, so no brackets)math.pi → 3.141592653589793
time.sleep (sec)Pauses the program for sec seconds, then carries on with the next linetime.sleep (0.5) → half-second pause
Worked exampleA bakery packs 50 cakes in boxes of 12. Work out the boxes needed, the full boxes and the cakes in the last box.
  1. import math
    
    CAKES_PER_BOX = 12
    
    cakes = 50
    boxesNeeded = math.ceil (cakes / CAKES_PER_BOX)
    fullBoxes = math.floor (cakes / CAKES_PER_BOX)
    inLastBox = cakes - fullBoxes * CAKES_PER_BOX
    print (boxesNeeded, fullBoxes, inLastBox)
  2. 50 ÷ 12 = 4.17 (to 2 d.p.). Rounded up: 5 boxes. Rounded down: 4 full boxes. 50 − 4 × 12 = 2 cakes in the last box.
Displays 5 4 2.
Exam tipExaminers said math.ceil was the reliable way to round up to whole packs. Home-made methods (adding 0.5, or int plus 1) went wrong when the number divided exactly.
math.ceil (x)
Returns the smallest integer greater than or equal to x.
math.floor (x)
Returns the largest integer less than or equal to x.
time.sleep (sec)
Suspends the program for sec seconds, then resumes at the next line.
Edexcel 1CP2 · 6.6.1

Turtle graphics

The turtle library draws pictures. A turtle moves around a canvas, trailing a pen behind it.

  • Setting up: import turtle, then turtle.mode ("standard"), screen = turtle.Screen (), screen.setup (WIDTH, HEIGHT), and create your turtle: theTurtle = turtle.Turtle (). Finish with turtle.done () so the window stays open.
  • Standard mode: the turtle starts at (0, 0), the centre, facing east (heading 0). Angles go anticlockwise (the PLS says “counterclockwise”): 90 is north, 180 west, 270 south. (Logo mode starts facing north and turns clockwise.)
  • Window commands use the library name or the screen variable (turtle.mode, turtle.Screen, turtle.screensize, turtle.done). Drawing commands use your turtle's name.
  • Moving: forward, back, left, right (degrees), setheading, setposition (x, y), home ().
  • The pen: penup () to move without drawing, pendown () to draw, pensize, pencolor ("navy"), speed ("fastest") (or 0).
  • Filling: fillcolor ("gold"), then begin_fill () before drawing the shape and end_fill () after it.
  • Circles: circle (radius). The centre is radius units to the turtle's left, so the turtle sits on the edge. circle (50, 180) draws a half circle.
  • hideturtle () and showturtle () hide or show the turtle's arrow.
  • A filled triangle:
    import turtle
    
    turtle.mode ("standard")
    pen = turtle.Turtle ()
    pen.fillcolor ("lime")
    pen.begin_fill ()
    for side in range (3):
        pen.forward (100)
        pen.left (120)
    pen.end_fill ()
    pen.hideturtle ()
    turtle.done ()
  • A regular shape with n sides turns 360 / n degrees at each corner: 120 for a triangle, 90 for a square, 60 for a hexagon.

Standard mode: (0, 0) is the centre, heading 0 is east and angles go anticlockwise. A circle's centre is to the turtle's left.

Exam tipUse the turtle the starting file creates (for example theTurtle), not the library name. Never write turtle = turtle.Turtle (): it replaces the library's name, and the next turtle. call crashes. Don't save your own file as turtle.py either.
Standard mode
The turtle starts facing east (heading 0) and angles are anticlockwise.
begin_fill () / end_fill ()
Called just before and just after drawing a shape, so the shape is filled with the fill colour.
Edexcel 1CP2 · 6.6.1, 6.6.2

Structuring a program with subprograms

  • Decompose the problem: one subprogram for each task, and a short main program that mostly calls them.
  • Choose a function when the calling code needs a value back (a calculation, a True/False check, a value the user enters). Choose a procedure when it only does something (display, draw, write).
  • Name subprograms after what they do: getChoice, isValidCode, showReport. A function returning True or False often starts with “is”.
  • Lay the file out in Pearson's sections, in this order: Import libraries, Constants, Global variables, Subprograms, Main program.
  • A patio tile calculator, decomposed:
    # -------------------------------------------------------------------
    # Import libraries
    # -------------------------------------------------------------------
    import math
    
    # -------------------------------------------------------------------
    # Constants
    # -------------------------------------------------------------------
    COVER_PER_BOX = 1.5       # Square metres one box of tiles covers
    
    # -------------------------------------------------------------------
    # Global variables
    # -------------------------------------------------------------------
    length = 0.0
    width = 0.0
    area = 0.0
    boxes = 0
    
    # -------------------------------------------------------------------
    # Subprograms
    # -------------------------------------------------------------------
    def patioArea (pLength, pWidth):
        total = pLength * pWidth
        return (total)
    
    def boxesNeeded (pArea):
        numBoxes = math.ceil (pArea / COVER_PER_BOX)
        return (numBoxes)
    
    def showResult (pArea, pBoxes):
        print ("Patio area: {:.1f} square metres".format (pArea))
        print ("Boxes of tiles to buy:", pBoxes)
    
    # -------------------------------------------------------------------
    # Main program
    # -------------------------------------------------------------------
    length = float (input ("Patio length in m: "))
    width = float (input ("Patio width in m: "))
    
    area = patioArea (length, width)
    boxes = boxesNeeded (area)
    showResult (area, boxes)
  • For a patio 4 m by 3.5 m, the area is 14.0 square metres and 10 boxes are needed (14 ÷ 1.5 = 9.33, rounded up).
  • Each subprogram can be tested on its own: print (boxesNeeded (15)) should show 10, and print (boxesNeeded (15.1)) should show 11.

A structure chart for the patio tile calculator: the main program calls three subprograms.

Exam tipOn the long Paper 2 questions, the Solution design level rewards a problem that has been “decomposed clearly into component parts”. Sensible subprograms with parameters and return values show that.
Decomposition (in code)
Breaking a program into subprograms, each doing one task, with a main program that calls them.
Subprogram interface
A subprogram's name, its parameters and what it returns: all another programmer needs to use it.
Edexcel 1CP2 · 6.6.1, 6.6.2, 6.6.3

Subprogram tasks in Paper 2

Paper 2 questions on subprograms ask you to complete, fix or write them in a starting file. These are the instructions that come up, and what earns the mark.

  • Use the constants the file gives you (PACK_SIZE), not the number they stand for.
  • Test a subprogram on its own before the main program uses it: call it with arguments where you know the answer, and print what comes back.
  • Keep each subprogram's work local: set its counters and totals inside it, so they start again from 0 each time it's called.
The instruction says…What earns the mark
Import the … libraryimport random (or math, time, turtle) under Import libraries
Add a procedure with no parameters to…A def name (): in Subprograms and a call in the main program
Complete the function so that it returns…return (value) on the last line, and the caller stores or uses the value
Change the names of the parametersNew names in the definition and all through the body
Call the subprogram with the correct argumentsThe right arguments, in the same order as the parameters
Use the parameter, not the globalThe global's name must not appear inside the subprogram
Generate a random indexrandom.randint (0, len (pList) - 1)
Work out the number of whole packsmath.ceil (items / PACK_SIZE) using the constant
Worked exampleThis function should return how many marks in a list reach the pass mark, but it never returns more than 1. Fix it.
def countPasses (pMarks, pPassMark):
    for mark in pMarks:
        count = 0
        if (mark >= pPassMark):
            count = count + 1
    return (count)
  1. Test it first: countPasses ([55, 72, 38, 90], 50) should be 3 but returns 1, and countPasses ([90, 20], 50) returns 0.
  2. The counter is set back to 0 every time round the loop, so only the last mark counts. The local counter must be set to 0 once, before the loop:
    def countPasses (pMarks, pPassMark):
        count = 0
        for mark in pMarks:
            if (mark >= pPassMark):
                count = count + 1
        return (count)
    
    print (countPasses ([55, 72, 38, 90], 50), countPasses ([90, 20], 50))
  3. Because count is local and set inside the function, every call starts again from 0.
Displays 3 1.
Exam tipDon't rewrite or delete the starting code. Change only what the # =====> comments ask for, then run the file with the test data given in the question.