Local and Global Variables
Parameter names and argument variable names are independent; the function receives the value, not the name.
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
- Before a function runs, Python marks every name assigned inside it as local to that function, unless it is declared global or nonlocal.
- Reading a name searches the local namespace, then enclosing functions, then the module's globals, then the built-ins; the first hit wins.
- A local name read before it has a value raises UnboundLocalError (Python does not fall back to the global).
- global x makes assignments go to the module namespace; nonlocal x makes them go to the nearest enclosing function.
- 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.
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.
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.
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.
hello
hello- 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.
goodbye
hello- 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?
Reveal 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.
Mistakes With Matching Names
Common mistake Believing the caller's variable must have the same name as the parameter
What it looks likedef print_twice(bruce): ... then calling print_twice(michael)Why it failsThe function receives the value, not the name. The caller's name and the parameter's name are independent labels.
Do this insteadPass 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 likeprint(bruce) written at the top level of the program, after print_twice(michael)Why it failsParameters exist only in the function's local scope and cannot be accessed from outside it.
Do this insteadUse 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 likeAssuming print(michael) shows 'goodbye' after change(michael) reassigns bruce
Why it failsReassigning bruce changes only the local name bruce. The caller's variable stays in its own scope.
Do this insteadIf 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
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.