Skip to content
ExamSpine

Lesson 4.7

Local and global scope

Part 4: FunctionsReading, about 6 min3 exercises in this lesson

Local and global scope

By the end of this you will be able to say where in a program a variable can be used, and predict what a program prints when a function and the main code both have a variable with the same name.

The part of a program where a variable can be used is called its scope. You have been writing functions for a few lessons now. This lesson sets out exactly which lines can use which variables.

A variable made in a function stays there

def make_label(name, score):
    label = name + ": " + str(score)
    return label

line = make_label("Mia", 8)
print(line)
public static void main(String[] args) {
    String line = makeLabel("Mia", 8);
    System.out.println(line);
}

static String makeLabel(String name,
                        int score) {
    String label = name + ": " + score;
    return label;
}

This prints Mia: 8. The variable label is made inside the function, so it is a local variable: it exists only while the function runs, and only the function's own lines can use it. When the function returns, label is gone. Only its value travels back, through the return, and the main code keeps that value in a variable of its own.

So a line in the main code that tried to print label would fail. In Python, the program would stop at that line with an error saying the name is not defined. In Java, the program would not compile, and the error would say the compiler cannot find the symbol.

Each call starts again from nothing. A second call to the same function makes a new label, with no memory of the last one.

Parameters are local too

A parameter is a local variable that the call fills in. You met this in lesson 4.2: the argument's value is copied into the parameter, so giving the parameter a new value inside the function changes nothing in the main code. Here it is again, in a function that returns a value.

def doublings(amount, goal):
    times = 0
    while amount < goal:
        amount = amount * 2
        times = times + 1
    return times

savings = 5
print(doublings(savings, 40))
print(savings)
public static void main(String[] args) {
    int savings = 5;
    System.out.println(
        doublings(savings, 40));
    System.out.println(savings);
}

static int doublings(int amount,
                     int goal) {
    int times = 0;
    while (amount < goal) {
        amount = amount * 2;
        times = times + 1;
    }
    return times;
}

This prints 3, then 5. Inside the function, amount goes from 5 to 10, 20 and 40, so the loop runs three times. But amount held only a copy of 5. The variable savings was never changed, so the last line prints 5.

Global variables

A variable that every function can use is called a global variable.

In Python, a variable made in the main code, outside every function, is global. Any function can read it, as long as the function does not make its own variable with that name (more on that below).

In Java, there are no true global variables: every variable is written inside a class. The nearest thing is a variable written in the class outside every method, with static in front. Java calls it a static field, and every static method in the class can use it. A variable made inside main is not like this: main is a method, so its variables are local to main, and no other method can see them.

pass_mark = 50

def passed(score):
    return score >= pass_mark

print(passed(72))
print(passed(38))
static int passMark = 50;

public static void main(String[] args) {
    System.out.println(passed(72));
    System.out.println(passed(38));
}

static boolean passed(int score) {
    return score >= passMark;
}

The function reads the pass mark without being given it, so the first line shows true and the second shows false (Python writes them True and False; Java writes true and false).

The same name, two variables

A function can make a local variable with the same name as a global one. They are still two separate variables. Inside the function, the name means the local one. Everywhere else, it means the global one.

width = 3

def area(length):
    width = length - 1
    return length * width

print(area(width + 4))
print(width)
static int width = 3;

public static void main(String[] args) {
    System.out.println(area(width + 4));
    System.out.println(width);
}

static int area(int length) {
    int width = length - 1;
    return length * width;
}

This prints 42, then 3. The call works out width + 4 first, using the global width, and hands over 7. Inside the function, width is a new local variable that holds 6, and the function returns 7 times 6. The last line is outside the function, so there width means the global one, which still holds 3.

What makes the variable inside the function a new one is different in each language:

  • In Python, when a function assigns a value to a name, that name is a local variable of the function. Here, the assignment inside the function is enough. (Python has a global line that changes this, but this course does not use it.)
  • In Java, a type in front of the name declares a new variable. Here, the int at the start of the assignment inside the method does that. Without the type, the assignment would change the static field instead.

This is useful. A helper can use a common name such as width or count for its own work, and it cannot spoil a variable of the same name somewhere else.

Two common slips

  • Expecting a function to change a variable in the main code by assigning to it inside the function. The assignment changes only the function's own variable. To get a new value out, return it, and assign the result to the variable in the main code.
  • Using a function's local variable after the function has returned. It no longer exists. Return the value instead, and keep it in a variable of the main code.

Now try it yourself on the questions below.

Exercise 4.7.1 · Trace itTrace: local scope

Complete the trace table for this Python code. [2]

Line 1: x = 10
Line 2:
Line 3: def make_five():
Line 4, indented 1 level: x = 5
Line 5, indented 1 level: return x
Line 6:
Line 7: result = make_five()
Line 8: print(x)
Line 9: print(result)

Fill in one row each time a line changes x or result, or prints something. The table already has the right number of rows. In each row, write only what that line changes; you can leave the other cells empty or copy their values down. Write values the way Python shows them: 3 and 3.0 are different, and text goes in quotes. In the output column, write exactly what appears on screen, with no quotes around it.

Rowxresultoutput
1
2
3
4
5

Exercise 4.7.1 · Trace itTrace: local scope (Java)

Complete the trace table for this Java code. [2]

Line 1: public static void main(String[] args) {
Line 2, indented 1 level: int x = 10;
Line 3, indented 1 level: int result = makeFive();
Line 4, indented 1 level: System.out.println(x);
Line 5, indented 1 level: System.out.println(result);
Line 6: }
Line 7:
Line 8: static int makeFive() {
Line 9, indented 1 level: int x = 5;
Line 10, indented 1 level: return x;
Line 11: }

Fill in one row each time a line changes x or result, or prints something. The table already has the right number of rows. In each row, write only what that line changes; you can leave the other cells empty or copy their values down. Write values the way Java shows them: 3 and 3.0 are different, and text goes in quotes. In the output column, write exactly what appears on screen, with no quotes around it.

Rowxresultoutput
1
2
3
4
5

Exercise 4.7.2 · Trace itTrace: param scope

Complete the trace table for this Python code. [2]

Line 1: def double(n):
Line 2, indented 1 level: n = n * 2
Line 3, indented 1 level: return n
Line 4:
Line 5: value = 3
Line 6: result = double(value)
Line 7: print(value)
Line 8: print(result)

Fill in one row each time a line changes value, n or result, or prints something. The table already has the right number of rows. In each row, write only what that line changes; you can leave the other cells empty or copy their values down. Write values the way Python shows them: 3 and 3.0 are different, and text goes in quotes. In the output column, write exactly what appears on screen, with no quotes around it.

Rowvaluenresultoutput
1
2
3
4
5
6

Exercise 4.7.2 · Trace itTrace: param scope (Java)

Complete the trace table for this Java code. [2]

Line 1: public static void main(String[] args) {
Line 2, indented 1 level: int value = 3;
Line 3, indented 1 level: int result = twice(value);
Line 4, indented 1 level: System.out.println(value);
Line 5, indented 1 level: System.out.println(result);
Line 6: }
Line 7:
Line 8: static int twice(int n) {
Line 9, indented 1 level: n = n * 2;
Line 10, indented 1 level: return n;
Line 11: }

Fill in one row each time a line changes value, n or result, or prints something. The table already has the right number of rows. In each row, write only what that line changes; you can leave the other cells empty or copy their values down. Write values the way Java shows them: 3 and 3.0 are different, and text goes in quotes. In the output column, write exactly what appears on screen, with no quotes around it.

Rowvaluenresultoutput
1
2
3
4
5
6

Exercise 4.7.34.7.3 · Answer itScope shadow

Look at this code. The first total is made outside any function, so every function can use it: it is a global variable (in Java, a static variable written in the class outside every method; Java calls it a static field).

total = 10

def reset():
    total = 0
    print(total)

reset()
print(total)
static int total = 10;

static void reset() {
    int total = 0;
    System.out.println(total);
}

// in main:
reset();
System.out.println(total);

It prints 0 and then 10. Explain why the second print shows 10, not 0. [2]