Concepts / Avoiding Global State in Functions

Avoiding Global State in Functions

Python localizes variables by default on assignment, making it impossible to modify global variables from functions without the global statement.

  • Programming

The Assignment Trap

A function can read a variable defined at the program's outermost level without a special declaration. Assignment is different. Python localizes a variable by default when a function assigns to that name, so the assignment does not modify the top-level variable unless the function uses the global statement.

What do you think happens?

A top-level variable named score starts at 5. A function assigns score = 10 without using global. Which score does the assignment change?

  • The top-level score

  • A local score used by the function

  • Both scores

  • Neither score

Reveal answer
Answer:

A local score used by the function

Python localizes variables by default when assignment occurs inside a function. Without global, the assignment does not modify the top-level variable.

Separate Bindings from One Name

Think of the top-level variable and the function's assigned variable as separate bindings. They may use the same name, but an assignment inside the function is localized by default. The function's assignment therefore does not change the value held by the top-level binding.

scoretop-level value: 5scorefunction-local value: 10same name, separate binding
Which binding changes when a function assigns to a name that also exists at the top level?
python

In this example, the function assigns to a localized score. The top-level score remains separate because the function did not declare score as global.

Reading Versus Writing

Operation inside a functionglobal statement required?Reason
Read a top-level variableNoReading a global variable works without global
Assign to a top-level variableYesAssignment is localized by default
Read and then assign to the same top-level variableYesThe function needs explicit global access before writing

The important distinction is between accessing a value and assigning to its name.

python

show_score reads the top-level score without global. increase_score writes to score, so it declares score as global before assigning to it. The declaration creates an explicit binding between the function's name and the outer-scope variable, allowing both read and write access.

Read scoreglobal not requiredglobal scoreread and write accessAssign scoreglobal requiredcan accessrequires declaration
Why can a function read a top-level variable without global but require global before assigning to it?

Making a Global Update

Worked example

Updating a top-level counter

A top-level variable named visits starts at 0. A function should increase that same variable each time it is called.

  1. 1
    Define the outer variable

    The program defines visits at the outermost level and gives it an initial value of 0.

  2. 2
    Declare the binding

    Inside the function, global visits explicitly connects the function's name visits to the top-level variable.

  3. 3
    Assign the updated value

    The function can now read the current top-level value and assign the increased value back to that same variable.

  4. 4
    Call the function repeatedly

    Each call changes the shared top-level state, so the next call starts with the value produced by the previous call.

Result

The function modifies the top-level visits variable rather than creating a separate function-local visits binding.

python
Output
visits is now 2
visits0record_visitfirst callvisits1record_visitsecond callvisits2reads and updatesvalue becomes 1reads and updatesvalue becomes 2
How does the top-level value change across repeated function calls when the function uses global?

This is a practical use of global: the function intentionally changes a variable defined at the outermost level. The shared value persists between calls, which is why the second call can update the result of the first call.

Clarity Costs of Shared State

Although global can make an update possible, global state can make a program harder to understand. A function that reads or changes shared outer-scope data has data flow that is less visible at the function call. The caller may need to know which global variables the function reads or changes, even though those variables are not listed as parameters or return values.

Shared global stateExplicit data flow
The function changes data held outside its parameter listThe function receives data through parameters
The result may remain in a shared outer-scope variableThe function returns the updated value
Code clarity and testability can be reducedThe input and output relationship is easier to see from the function interface

Prefer parameters and return values when they express the intended data flow clearly.

python

The first function changes shared global state. The second function receives a value and returns an updated value instead. The second style makes the data entering and leaving the function explicit, which supports clearer code when shared state is not necessary.

Mistakes to Avoid

  • Common mistake

    Assuming that assignment inside a function automatically changes the top-level variable

    What it looks like

    A function assigns score = 10 while a separate top-level score already exists.

    Why it fails

    Python localizes variables by default on assignment inside a function.

    Do this instead

    Use global score before the assignment if the function must modify the top-level score.

  • Common mistake

    Using global when the function only needs to read a top-level variable

    What it looks like

    A function returns the current value of score but never assigns to score.

    Why it fails

    Reading a global variable works without global.

    Do this instead

    Omit global when the function only reads the value.

  • Common mistake

    Reading and assigning to the same global name without declaring it

    What it looks like

    A function tries to increase score by reading score and then assigning a new value, but has no global statement.

    Why it fails

    Mixing reads and writes without global can cause UnboundLocalError.

    Do this instead

    Declare the name as global before the read-and-write operation, or redesign the function to use a parameter and return value.

  • Common mistake

    Using global by default for ordinary data flow

    What it looks like

    A function changes shared state even though the caller could pass the current value and receive the updated value.

    Why it fails

    Global state reduces code clarity and testability.

    Do this instead

    Prefer passing data through parameters and return values when that expresses the operation clearly.

Practice the Decision

MEDIUM

For each situation, decide whether the function needs global. Then decide whether using a parameter and return value would make the data flow clearer.

Situation 1: A function only reads a top-level setting and uses that value in its result. Situation 2: A function must increase a top-level counter that persists across calls. Situation 3: A function receives a number, calculates an updated number, and does not need to preserve shared state.

Hints
  • Separate reading from assigning.
  • Look for the situation where the function must modify a top-level variable.
  • Ask whether the updated value can be returned instead of stored globally.
  • Situation 1 does not require global because the function only reads the top-level value.
  • Situation 2 requires global if the function directly modifies the top-level counter.
  • Situation 3 does not require global; parameters and a return value make the data flow explicit.

Working Rule

  1. 1
    Assignment inside a function is localized by default, so it does not modify a top-level variable with the same name. Reading a top-level variable does not require global, but writing to it does. The global statement explicitly connects the function's name to the outer-scope variable and permits read and write access. Use global only when shared state is genuinely needed; otherwise, prefer parameters and return values because they make data flow clearer and support better testability.

Key Takeaways

  • Python localizes a variable by default when a function assigns to that name.
  • A function can read a top-level variable without global.
  • A function needs global before it can assign to a top-level variable.
  • Mixing reads and writes without global can cause UnboundLocalError.
  • Prefer parameters and return values when they make data flow clearer than shared global state.

Related concepts

More concepts starting with A