B2.1.1 · Programming fundamentals
Global and local variables of various data types
Two questions decide everything on this statement: what kind of value is this, and which part of the program is allowed to see it.
Explainer
Northgate Swim Club keeps a whiteboard by the pool door. One line never changes all season: the pool is 25 metres long. Another line is rubbed out and rewritten every time somebody finishes a session: the number of swims logged today. Both are just labelled spaces holding a value, but one is written once and read by everybody, while the other is updated constantly. A program stores information the same way, and gives you control over both things: what kind of value the space can hold, and who is allowed to look at it.
A variable is a named space in memory holding a value that the program can read and change while it runs. The name is how the rest of the program refers to that space, so laps means "whatever is currently stored under the name laps", not one fixed number.
A data type states what kind of value a variable is allowed to hold, and therefore what can legally be done with it. Two numbers can be subtracted; two pieces of text cannot. The type is what lets the language decide whether an operation makes sense before it runs it.
A value that is fixed for the whole run, like the 25 metre pool length, is a constant. It is still a named space in memory, but the program never reassigns it. Markers report students losing marks for listing a constant when asked for variables, and the reverse, so read the question's wording carefully: if the value is written once and never changed, it is a constant.
Explainer
The five data types this statement names
The syllabus lists exactly five, and every one of them shows up in the swim club program below. Python works out the type from the value you assign, while Java makes you state it before the name. Both are examinable, so read each row across.
| Data type | Holds | Python | Java |
|---|---|---|---|
| integer | A whole number, no fractional part | laps = 24 | int laps = 24; |
| decimal | A number with a fractional part | pace = 31.75 | double pace = 31.75; |
| string | Text of any length, including empty | swimmer = "Chloe" | String swimmer = "Chloe"; |
| char | Exactly one character | No char type: use a one-character string, lane = "B" | char lane = 'B'; |
| Boolean value | Only True or False | is_member = True | boolean isMember = true; |
Java has a real char type written with single quotes, and Python does not: a single character in Python is just a string of length one. Java also writes its Boolean values in lower case (true), while Python capitalises them (True). Writing true in Python is a name error, not a Boolean.
Choosing the type is a real decision, not decoration. Storing a lap count as a string means "24" + "1" gives "241" rather than 25, because joining text is a perfectly legal thing to do with two strings. Markers report answers losing marks for exactly this: a value stored under a type that cannot support the operation the question then asks for.
Explainer
Global and local: who can see the variable
Scope is the second half of this statement, and it is about visibility and lifetime rather than value. The deciding question is where the variable was created.
A global variable is created outside every function, at the top level of the program. It can be read anywhere in the file, and it stays in memory for as long as the program runs.
A local variable is created inside a function. It exists only while that function is running, and the moment the function returns, the name disappears and its memory is released. Code outside the function cannot see it at all.
Java is an object-oriented language, so every variable lives inside some class, there is no bare top-level name the way Python allows. The closest equivalent to a global is a static field of a class: one shared copy that exists for the whole run of the program and is reachable from any method, with none of the per-call creation a local variable gets.
| Question | Global variable | Local variable |
|---|---|---|
| Where is it created? | Outside every function | Inside a function body |
| Who can read it? | Any code in the file | Only that function |
| How long does it live? | The whole run of the program | Only while that call is running |
| How many exist at once? | One | A fresh one per call |
Reading a global from inside a function needs nothing special. Writing to one does. In Python, assigning to a name inside a function creates a local variable by default, even when a global of the same name already exists, so the global is left untouched and the change silently disappears when the function returns. The global keyword is how you say you meant the outer one.
# the trap: this does NOT change the global session_count = 0 def log_swim(): session_count = session_count + 1 # makes a brand new LOCAL, then fails reading it # the fix: say which one you mean def log_swim(): global session_count # "the outer one, not a new local" session_count = session_count + 1
Java needs no equivalent to the global keyword. A static field is written to directly from any method, no declaration required first, since it already belongs to the class rather than to any one method call.
// the Java equivalent: sessionCount is a static field of the class public class Pool { static int sessionCount = 0; // one shared copy, not per-call static void logSwim() { sessionCount = sessionCount + 1; // writes straight to the class's copy } }
There is no risk of accidentally creating a new local here the way Python's default behaviour allows, a bare sessionCount = sessionCount + 1 inside a method always means the class's own static field.
Worked example
Tracing the program line by line
This is the command term the statement actually names, and it is marked on completeness, not just on the final answer. Below is the Northgate program in full, then a trace of what memory holds at each step.
POOL_LENGTH = 25 # global constant: every lane is 25 m session_count = 0 # global variable: swims logged so far def record_swim(swimmer, laps, seconds): global session_count distance = laps * POOL_LENGTH # local: integer pace = seconds / laps # local: decimal session_count = session_count + 1 print(swimmer, "swam", distance, "m, average lap", round(pace, 1), "s") record_swim("Chloe", 24, 762) record_swim("Tomas", 16, 528) print("sessions:", session_count)
Give every variable in the program its own column, globals and locals alike, before you run a single line. Work out how many columns you need by reading the code, not by discovering them as you go. Markers report that the most common lost mark on a trace is a missing column for a variable the program clearly uses, and the second is leaving a cell dashed or blank once that variable already holds a value. Once a variable has a value, every later row repeats it unless a line changes it.
Step 1. The two globals are created. Nothing has been called yet. Both names live at the top level, so they will still be here when the program ends.
Step 2. The first call begins. The three parameters are locals too. They are created fresh for this call and hold the values passed in.
Step 3. The two calculated locals appear. distance reads the global POOL_LENGTH, which needs no keyword because it is only being read. Note the types: 24 × 25 is an integer, while 762 ÷ 24 produces a decimal.
Step 4. The global is updated, then the call ends. Because of the global line, this writes to the outer session_count. Then the function returns and every local is destroyed. This is the step students most often get wrong on a trace.
Step 5. The second call. A completely new set of locals, holding different values. Nothing survives from Chloe's call, which is exactly why the same function can be reused safely.
Step 6. Back at the top level. The final line can read session_count because it is global. It could not print distance, because that name no longer exists anywhere.
Written as a trace table, the same six steps look like this. Every variable has a column from the start, and a value repeats down the rows until something changes it.
| Line | POOL_LENGTH | session_count | swimmer | laps | seconds | distance | pace |
|---|---|---|---|---|---|---|---|
| globals created | 25 | 0 | no call running | ||||
| call 1 begins | 25 | 0 | "Chloe" | 24 | 762 | ||
| locals calculated | 25 | 0 | "Chloe" | 24 | 762 | 600 | 31.75 |
| global updated, call ends | 25 | 1 | locals destroyed | ||||
| call 2 runs | 25 | 2 | "Tomas" | 16 | 528 | 400 | 33.0 |
| final print | 25 | 2 | locals destroyed | ||||
Explainer
Choosing between global and local
B2 asks how programming is applied to solve problems, and scope is one of the places where that choice is made explicitly rather than by habit. The deciding question is short: does anything outside this function genuinely need this value?
Real example: distance and pace inside record_swim, working values that only exist to produce one printed line.
Advantage
- Nothing outside the function can read or change it (a bug in one function cannot corrupt another's values, so each function can be tested and fixed on its own)
- Memory is released the moment the call ends (a program calling a function thousands of times never accumulates thousands of leftover values)
Disadvantage
- The value is lost when the function returns (anything the rest of the program needs must be returned explicitly or it disappears)
Real example: session_count, a running total that has to survive between calls, and POOL_LENGTH, one fixed fact the whole program shares.
Advantage
- The value persists across every call (a running total is impossible with a local, since each call would start it again from zero)
- One shared copy every function can read (changing the pool length is a single edit rather than one per function)
Disadvantage
- Any function can change it (when the value comes out wrong, every function in the file is a suspect, so the bug is far harder to locate)
- It occupies memory for the entire run (the space is never released, even during the long stretches when nothing is using it)
The working rule: make everything local by default, and promote a variable to global only when something genuinely has to outlive a single call, like a running total or a fixed setting. A global chosen out of convenience is the most common source of bugs that are hard to trace.
Try it yourself
Run the Northgate program
The same program as the trace above, live and editable. Two experiments are waiting at the bottom: delete the global line and watch the count stop rising, then try to print a local from outside its function and read the error Python gives you.
Running in offline fallback mode. The full Python engine couldn't load (blocked school network, or no internet), so this console switched automatically to a small hand-written engine. It runs this page's scenario, including global and local scope, but it isn't full Python: one visible difference is that whole-number decimals print as 33 here rather than Python's 33.0.
Check your understanding
A program sets total = 0 at the top level. A function then runs total = total + 5 with no global line. The program prints total after the call. What happens?
Common mistake
B2.1.1RecurringThe most reported loss on this statement is not a wrong calculation, it is an incomplete trace table. Answers leave out a column for a variable the program plainly uses, often a temporary working value, and lose the marks tied to it even when every other number is right.
The second reported pattern is presentation inside the table: variables that the program initialises are left uninitialised in the trace, and cells are filled with dashes partway down even though the variable already holds a value from an earlier row. A trace is read as a record of memory, so a blank cell claims the variable holds nothing.
Markers also report integer division being traced as if it produced a decimal. In Python 762 // 24 is 31, not 31.75, and the discarded remainder changes every row that follows.
A related habit shows up on the construction side, not just the tracing side: a variable meant to accumulate, like session_count above, only works if it starts from a genuine initial value. Declaring a counter or a running total without giving it one produces a wrong answer, or an error, from the very first use, and it is exactly the kind of missing detail that is easy to skip when the surrounding logic is otherwise correct.
Answer frame that scores: one column per variable before you start → fill every cell on every row → carry a value down unchanged until a line actually changes it → check every counter and total was given a starting value before the loop that uses it begins.
What a weak trace looks like: columns for laps and session_count only, with distance missing entirely and pace shown as a dash on the rows after it was calculated. The arithmetic may be perfect, but the marks attached to the missing variable cannot be awarded.
What it should look like: a column for each of POOL_LENGTH, session_count, swimmer, laps, seconds, distance and pace, drawn before tracing began, with each value repeated down the rows until a line changes it and the locals marked as destroyed when the call ends. Complete, and readable as a record of what memory held.
Linking question
How this connects to the rest of the syllabus
The IB syllabus is deliberately woven together, not a stack of isolated topics. Here's how variables and scope connect specifically to A1 (computer fundamentals).
Why is an understanding of variables and their scope important for effective memory management in computer systems? (The stepper above shows the answer directly: the five locals in record_swim occupy memory only while that call is running and are released the instant it returns, whereas both globals hold their space for the entire program. A function called ten thousand times reuses the same small block of memory ten thousand times, which is only possible because scope tells the system exactly when a value stops being needed.)
Revision questions
Past-paper style. Write an answer, then reveal the marking points and mark yourself.
[2]Distinguish between a global variable and a local variable.
Marking points
评分要点
- A global variable is declared outside any function and is visible throughout the program, keeping its value between calls.
- A local variable is created inside a function, exists only while that function runs, and cannot be accessed from outside it.
- 全局变量在任何函数之外声明,在整个程序中可见,并在调用之间保持其值。
- 局部变量在函数内部创建,只在该函数运行时存在,无法从函数外部访问。
[4]A program stores a swimmer's lane as a single letter and their membership status as either true or false. State the data type of each, and justify both choices.
Marking points
评分要点
- Lane as a single letter: character (CHAR) type, because it is exactly one letter and no arithmetic is done on it.
- Membership status as true or false: boolean type, because it has exactly two states.
- Justify CHAR: a fixed single character is stored compactly and cannot hold an invalid multi-character value.
- Justify boolean: it makes the two-state meaning explicit and cannot drift into inconsistent text like yes / Yes / y.
- 泳道用单个字母:字符(CHAR)类型,因为它正好是一个字母,且不对它做算术。
- 会员状态为真或假:布尔类型,因为它正好有两个状态。
- CHAR 的理由:固定的单个字符存储紧凑,且不能持有无效的多字符值。
- 布尔的理由:它把两态的含义表达清楚,且不会漂移成 yes / Yes / y 这样不一致的文本。
[5]Construct a trace table for the record_swim function when it is called twice, showing every global and local variable.
Marking points
评分要点
- Globals: POOL_LENGTH = 25 (constant), session_count starts at 0.
- Call 1 record_swim(Chloe, 24, 762): local distance = 24 * 25 = 600; local pace = 762 / 24 = 31.75; session_count becomes 1; output Chloe swam 600 m, average lap 31.8 s.
- Call 2 record_swim(Tomas, 16, 528): local distance = 16 * 25 = 400; local pace = 528 / 16 = 33.0; session_count becomes 2; output Tomas swam 400 m, average lap 33.0 s.
- After both calls the global session_count = 2, and the local distance and pace from call 1 no longer exist.
- The trace table should show one row per call with columns for session_count (global) and distance and pace (local).
- 全局变量:POOL_LENGTH = 25(常量),session_count 从 0 开始。
- 调用 1 record_swim(Chloe, 24, 762):局部 distance = 24 * 25 = 600;局部 pace = 762 / 24 = 31.75;session_count 变为 1;输出 Chloe swam 600 m, average lap 31.8 s。
- 调用 2 record_swim(Tomas, 16, 528):局部 distance = 16 * 25 = 400;局部 pace = 528 / 16 = 33.0;session_count 变为 2;输出 Tomas swam 400 m, average lap 33.0 s。
- 两次调用后全局 session_count = 2,而调用 1 的局部 distance 和 pace 已不再存在。
- 追踪表应每次调用一行,列包括 session_count(全局)以及 distance 和 pace(局部)。
Flashcards
Active recall for this statement’s key terms.
Keep this statement’s practice with you
Free account: unlock every revision question and flashcard for B2.1.1, and every other IB CS 2027 statement.