Concepts / Local and Global Variables

Local and Global Variables

Parameter names and argument variable names are independent; the function receives the value, not the name.

  • Programming
Interactive lab

Try it: Scope: Local, Enclosing, Global, Built-in

How Python looks up a name Local → Enclosing → Global → Built-in, why assigning to a name inside a function makes it local (and raises UnboundLocalError if it is read first), and what global, nonlocal and closures change.

How it works

  1. Before a function runs, Python marks every name assigned inside it as local to that function, unless it is declared global or nonlocal.
  2. Reading a name searches the local namespace, then enclosing functions, then the module's globals, then the built-ins; the first hit wins.
  3. A local name read before it has a value raises UnboundLocalError (Python does not fall back to the global).
  4. global x makes assignments go to the module namespace; nonlocal x makes them go to the nearest enclosing function.
  5. A function's local frame disappears when it returns, unless an inner function (a closure) still uses its variables.

Default run (10 steps): Ready: Local shadows global. Every name is looked up Local, then Enclosing, then Global, then Built-in. … Finished. Printed: inside: 99 / outside: 10.

Simplified: The lab's own small Python interpreter runs a fixed, hand-written script (you choose the variant and the values, never the code); nothing is executed as real Python. Every script was run in CPython 3.12 with the same inputs and the lab reproduces its output and error messages. Built-ins shows only the names the script used.

Educational simulation

Loading the simulation…

The Matching-Names Assumption

Many learners assume that when a variable is passed to a function, its name must match the name of the parameter inside the function. If a function has a parameter called bruce, it seems you could only pass it a variable named bruce. This is a natural assumption, because names matter a great deal in programming. But it is incorrect, and understanding why is essential to using function calls well.

A helpful way to picture this is a package sent through the mail. The package arrives carrying a label from the sender, which is the caller's variable name. When it reaches the destination, the recipient, which is the function, attaches a new label based on how they want to refer to it. The contents, the actual value, stay the same. Only the label changes. The function does not care what label the package had before. It cares about the contents and the name it assigns.

Tracing a Value From Caller to Function

Consider a caller whose variable is named michael and holds the value 'hello'. When print_twice(michael) is called, the value 'hello' is passed into the function. Inside the function, that value is assigned to the parameter bruce. From that point on, within the function, the value is referred to only as bruce. The name michael has no meaning inside the function. The function never sees it.

michaelcaller's variable'hello'the valuebrucefunction's parameterholdspassed in as argument
When michael is passed to print_twice, the value 'hello' is bound to the parameter bruce. The caller's name and the parameter's name are two separate labels on the same value.

Notice what the diagram shows. The value is the thing that moves across the call. The name michael belongs to the caller, and the name bruce belongs to the function. The function receives the value, not the name. This is why the function works correctly with any variable, as long as the value is passed in.

Where Parameter Names Live

Python organizes names into scopes. The global scope is the outermost level, where variables defined at the top level of a program exist. Each function has its own local scope. Every parameter lives in the local scope of its function. It is meaningful only inside that function's body, and it cannot be accessed from outside the function or from inside other functions.

global scopetop level of the programmichael'hello'bruceparameterprint_twice localscopeexists only during the callcontainscontainscontains
The caller's variable michael lives in the global scope. The parameter bruce lives only in the local scope of print_twice, and disappears when the function finishes.

The lifetime of a parameter follows its scope. When the function is called, the parameter is created in the local scope and assigned the argument's value. When the function finishes, the parameter ceases to exist. The caller's variable stays in the caller's scope the whole time and is unaffected by what happened inside the function. This isolation is by design. It allows different functions to use the same parameter names without conflicting with one another.

python
Output (expected)
hello
hello
Notes on the code
  • michael is a global variable, created at the top level of the program
  • bruce is a parameter, visible only inside print_twice
  • The call passes the value of michael, so bruce receives 'hello'

Reassigning a Parameter Inside a Function

Because the parameter is a separate name, the function can assign a new value to it. That change affects only the parameter. The variable with the original name in the caller keeps its own value. The example below shows the function giving bruce a new value, then the caller printing its own variable.

python
Output (expected)
goodbye
hello
Notes on the code
  • Inside change, bruce is reassigned to 'goodbye'
  • michael in the caller was never reassigned, so it still holds 'hello'

What do you think happens?

After change(michael) finishes, what does print(michael) show?

  • 'goodbye'

  • 'hello'

  • A NameError

Reveal answer
Answer:

'hello'

The function assigned a new value only to its own parameter bruce. The caller's variable michael stays in the caller's scope and is unaffected by what happened inside the function.

michael'hello'michael'hello'bruce'hello'bruce'goodbye'
Before the reassignment, michael and the parameter both refer to 'hello'. After bruce is reassigned, only bruce changes. michael still holds 'hello'.

Mistakes With Matching Names

  • Common mistake

    Believing the caller's variable must have the same name as the parameter

    What it looks like
    def print_twice(bruce): ... then calling print_twice(michael)
    Why it fails

    The function receives the value, not the name. The caller's name and the parameter's name are independent labels.

    Do this instead

    Pass any variable you like. The function works as long as a value is passed in.

  • Common mistake

    Using a parameter name outside its function

    What it looks like
    print(bruce) written at the top level of the program, after print_twice(michael)
    Why it fails

    Parameters exist only in the function's local scope and cannot be accessed from outside it.

    Do this instead

    Use the caller's own variable outside the function, such as michael, or return a value from the function.

  • Common mistake

    Expecting a reassigned parameter to change the caller's variable

    What it looks like

    Assuming print(michael) shows 'goodbye' after change(michael) reassigns bruce

    Why it fails

    Reassigning bruce changes only the local name bruce. The caller's variable stays in its own scope.

    Do this instead

    If the caller needs a new value, have the function return it and assign the result in the caller.

Calling a Function With Your Own Variable Names

EASY

Given the function def double(number): return number * 2, write a call that doubles the value stored in a variable named total. Do not rename the parameter or the variable to match each other.

Hints
  • The parameter in the definition is number, but the call can use any variable name.
  • Pass total directly as the argument, then decide what to do with the returned value.

Key Takeaways

  • Argument names and parameter names are independent. A function receives the value, not the caller's variable name.
  • Inside a function, the value is referred to only by the parameter name, such as bruce, and the caller's name, such as michael, has no meaning there.
  • Parameters live in the function's local scope. They exist only during the call and cannot be accessed from outside the function.
  • Reassigning a parameter inside a function does not change the caller's variable with the original name.
  • Because names are independent, you can write a function once and call it with any variable in your program.

Related concepts

More concepts starting with L