Concepts / Variable Scope and Namespace

Variable Scope and Namespace

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

  • Programming

A Name Can Belong to Different Scopes

A variable name does not automatically refer to one universally shared place. Python organizes names through namespaces, and a function has its own local namespace while the program also has an outermost namespace. The important rule for this lesson is that Python localizes a variable by default when a function assigns to that name. This is why a function cannot modify a top-level variable through assignment unless it explicitly uses the global statement.

assigns to countercreates local bindingOutermost namespacecounterFunction namespacecounterAssignmentlocal by default
Which namespace receives a name when a function assigns to it?

The same spelling can appear in the outermost namespace and inside a function, but assignment inside the function is local by default.

Trace an Assignment Without global

What do you think happens?

Suppose the outermost namespace contains score with the value 10. A function assigns score = 20 without a global statement. Which binding does that assignment change?

  • The outermost score binding
  • A local score binding inside the function
  • Both bindings
  • Neither binding
Reveal answer

Answer: A local score binding inside the function

Python localizes names by default when a function assigns to them. The assignment does not modify the outermost variable.

score = 10 def set_score(): score = 20 set_score()

assignment creates local bindingouter value remains availablescore10score20set_score
What changes when a function assigns to a same-named variable instead of only reading the outermost value?

Reading Versus Writing

Reading a global variable from inside a function works without global. Writing to that global variable requires the global statement. This distinction matters when a function both reads and writes a name: without global, Python treats the assigned name as local, so the function cannot use that same name as an outer-scope value in the intended way. The source identifies this mixed read-and-write situation as causing UnboundLocalError.

python
Output
The function can read the outermost limit without declaring global.
python
Output
The global statement makes the function's count name refer to the outermost count binding, so the assignment can modify it.
reads without globaldeclares shared bindingpermits writeshow_limitRead limitincrease_countglobal countAssign count
What is the difference between a function that reads a global value and one that changes shared global state?

Declare the Shared Binding

The global statement creates an explicit binding between a local name and a global name. Place the statement inside the function before the assignment that must change the outermost variable. After that declaration, the function has both read and write access to the outer-scope variable.

visits = 0 def record_visit(): global visits visits = visits + 1 record_visit() record_visit()

enter functionuse global bindingcompute new valuewrite shared stateFunction callglobal visitsRead visitsAssign visitsUpdated outermostvalue
How does control flow and variable lookup change when a function declares a name with global before assigning to it?

Use global only when a function genuinely needs to modify a variable defined in the program's outermost namespace. Keeping the declaration close to the function's assignment makes the shared state visible to readers of the code.

Observe the State Change

function callassignment completesstatuswaitingstart_taskglobal statusstatusrunning
How does a global variable's value change before, during, and after a function call that uses global?

This example shows the defining effect of global: the function is not merely creating a temporary local name. It is changing shared state in the outermost namespace, and later code that uses that outermost name can observe the new value.

Clarity and Safer Data Flow

A global variable can be convenient, but global state reduces code clarity and testability. A function that changes shared state has an effect that is not visible from its parameters or return value. This makes it harder to see where data comes from and where it changes. The recommended default is to pass data through parameters and return values, using global only when necessary.

ApproachData movementClarity concern
Read a global valueThe function obtains a value from outer-scope stateThe dependency is outside the parameter list
Write a global valueThe function changes shared outer-scope stateThe side effect may be harder to track and test
Use parameters and return valuesThe caller supplies data and receives a resultThe data flow is more explicit
python
python

The first version changes shared state through global. The second version makes the input and result explicit with a parameter and a return value. When the second design fits the task, it is usually easier to understand and test because the function's data flow is visible at the call site.

Mistakes with Global Names

  • Expecting assignment inside a function to update the outermost variable automatically.

    Python localizes variables by default on assignment, so the assignment creates or updates a local binding.

    Fix: Use global score before the assignment if modifying the outermost score is genuinely required.

  • Reading and writing a global name without declaring it global.

    The source identifies mixing reads and writes without global as causing UnboundLocalError.

    Fix: Declare global count before the assignment, or redesign the function to receive count as a parameter and return the new value.

  • Using global for every value shared with a function.

    Global state reduces code clarity and testability.

    Fix: Prefer passing data through parameters and return values when that communicates the data flow clearly.

Practice the Binding Decision

MEDIUM

For each situation, decide whether the function needs global. Then explain why. 1. A function only reads an outermost variable called limit. 2. A function assigns a new value to an outermost variable called mode. 3. A function receives a value as a parameter and returns an updated value without changing any outermost variable. 4. A function both reads and assigns count using the same name, but has no global statement.

Hints
  • Reading a global variable does not require global.
  • Writing to a global variable requires global.
  • Parameters and return values make data flow explicit.
  • The mixed read-and-write case without global causes UnboundLocalError.

Choosing a binding strategy

A program has an outermost variable called attempts. A function should increase it each time it is called. What must the function do, and what alternative design could make the data flow clearer?

Identify the operation: The function must write a new value to a variable defined in the outermost namespace.

Apply the binding rule: Assignment inside a function is local by default, so the function needs global attempts before assigning to the outermost attempts.

Consider the design: Because global state can reduce clarity and testability, another design is to pass attempts as a parameter and return the increased value.

Use global attempts when modifying the shared outermost variable is necessary; otherwise prefer an explicit parameter-and-return-value design.

Key Takeaways

  1. Python localizes a name by default when a function assigns to it.
  2. Reading a global variable works without global, but writing to it requires global.
  3. The global statement explicitly binds the function's name to the outermost name, allowing reads and writes.
  4. Mixing reads and writes without global causes UnboundLocalError.
  5. Global state can reduce clarity and testability, so prefer parameters and return values when they make data flow explicit.

Key Takeaways

  • Assignment inside a function is local by default.
  • Use global before assigning to a variable defined in the program's outermost namespace.
  • Reading a global does not require global, but mixing a read and write without it causes UnboundLocalError.
  • Use global sparingly because shared global state can reduce clarity and testability.
  • Prefer parameters and return values when they provide a clearer data flow.