14.1 Understanding Scope
Scope means the part of a program where a name can be found and used. A variable created inside a function usually belongs only to that function, while a variable created outside functions can often be read in many places. Understanding scope helps beginners avoid name errors and prevents one part of a program from changing data unexpectedly.
Example
name = "Global name"
def show_name():
local_name = "Local name"
print(name)
print(local_name)
show_name()
Output
Global name
Local name
Output explanation: The function can read the global variable name, and it can also read its own local variable local_name. Both values are available while the function runs, so both lines are printed.
14.2 Local Scope
Local scope is created when Python enters a function. Variables assigned inside that function normally exist only inside it. Other functions and code outside the function cannot directly use those local names. Local scope is helpful because it keeps temporary information private and reduces accidental conflicts between variables that happen to use the same name.
Example
def greet():
message = "Hello from the function"
print(message)
greet()
Output
Hello from the function
Output explanation: The variable message is created inside greet(), so it belongs to the function's local scope. The function prints it successfully while it is running.
14.3 Global Scope
Global scope contains names created at the main level of a Python file, outside functions and classes. A global variable can normally be read inside functions, although changing it requires special care. Global values are useful for settings that many parts of a program need, but too many global variables can make a program difficult to understand.
Example
school = "Greenwood School"
def show_school():
print(school)
show_school()
print(school)
Output
Greenwood School
Greenwood School
Output explanation: The variable school is created in global scope. The function reads it, and the main program reads it again, so the same text appears twice.
14.4 Enclosing Scope
Enclosing scope appears when one function is placed inside another function. The inner function can usually read variables belonging to the outer function. This scope sits between local and global scope in Python's name-search order. It is especially useful for helper functions, closures, and programs that need to remember information from an outer function.
Example
def outer():
message = "From the outer function"
def inner():
print(message)
inner()
outer()
Output
From the outer function
Output explanation: The inner function does not create message, so Python looks in the enclosing outer function. It finds the variable there and prints its value.
14.5 Built-In Scope
Built-in scope contains names that Python provides automatically, such as print, len, sum, min, max, and type. These names are available without creating or importing them. Beginners should avoid using built-in names for their own variables because doing so can hide the original built-in function and cause confusing errors later in the program.
Example
numbers = [4, 7, 2]
print(len(numbers))
print(max(numbers))
Output
3
7
Output explanation: Python finds len and max in built-in scope. len() reports three list items, and max() returns the largest value, which is 7.
14.6 The LEGB Rule
LEGB describes the order Python follows when searching for a name: Local, Enclosing, Global, and Built-in. Python stops as soon as it finds a matching name. Learning this rule helps beginners predict which value a program will use when the same variable name appears in more than one scope.
Example
value = "global"
def outer():
value = "enclosing"
def inner():
value = "local"
print(value)
inner()
outer()
Output
local
Output explanation: Inside inner(), Python first checks local scope. It immediately finds value = "local", so it prints local and does not continue searching enclosing or global scope.
14.7 Local Variables
A local variable is created inside a function and is intended for work performed by that function. It normally begins to exist when the function runs and becomes unavailable after the function finishes. Local variables make functions safer because their temporary values do not automatically interfere with variables used elsewhere.
Example
def calculate_total():
price = 12
quantity = 3
total = price * quantity
print(total)
calculate_total()
Output
36
Output explanation: The local variables price, quantity, and total exist inside the function. Python multiplies 12 by 3 and prints 36.
14.8 Global Variables
A global variable is created outside functions at the top level of a file. Functions can normally read its value, which makes it useful for shared settings or fixed information. However, changing global variables from many places can make a program unpredictable, so beginners should use them carefully and prefer function parameters when possible.
Example
tax_rate = 0.13
def add_tax(price):
return price + price * tax_rate
print(add_tax(100))
Output
113.0
Output explanation: The function reads the global variable tax_rate. It adds 13 percent of 100 to the original price, so the returned and printed result is 113.0.
14.9 The global Keyword
The global keyword tells Python that an assignment inside a function should change a variable from global scope instead of creating a new local variable. It should be used sparingly because changing shared state can make code harder to follow. For many programs, returning a value is clearer than modifying a global variable.
Example
score = 0
def add_point():
global score
score = score + 1
add_point()
print(score)
Output
1
Output explanation: The global score statement connects the name inside the function to the global variable. The function increases that shared value from 0 to 1, and the main program prints 1.
14.10 The nonlocal Keyword
The nonlocal keyword is used inside a nested function when you need to change a variable belonging to an enclosing function. Without nonlocal, assigning to that name would create a new local variable in the inner function. This keyword is useful in closures, counters, and small functions that remember changing state.
Example
def make_counter():
count = 0
def increase():
nonlocal count
count += 1
return count
return increase
counter = make_counter()
print(counter())
print(counter())
Output
1
2
Output explanation: The inner function changes the enclosing variable count because it uses nonlocal. The first call changes it to 1, and the second call changes the remembered value to 2.
14.11 Nested Functions and Scope
A nested function is a function defined inside another function. It can use its own local variables, read values from the enclosing function, and access global or built-in names when needed. Nested functions are useful when a helper operation belongs only to one larger function and should not be available everywhere in the program.
Example
def prepare_message(name):
greeting = "Welcome"
def combine():
return greeting + ", " + name
return combine()
print(prepare_message("Lina"))
Output
Welcome, Lina
Output explanation: The nested function reads greeting and name from the enclosing function. It combines them into one string, which the outer function returns and print() displays.
14.12 Variable Shadowing
Variable shadowing happens when a name in a smaller scope has the same spelling as a name in a larger scope. The nearer variable temporarily hides the outer one in that scope. Shadowing is legal, but it can confuse beginners, so using clear and different names is often a better choice.
Example
color = "blue"
def show_color():
color = "green"
print(color)
show_color()
print(color)
Output
green
blue
Output explanation: Inside the function, the local variable color shadows the global variable, so green is printed. Outside the function, the global value remains blue.
14.13 Namespaces
A namespace is a mapping that connects names to objects. Python keeps separate namespaces for built-in names, modules, functions, classes, and other scopes. You can imagine a namespace as a labelled table showing which value belongs to each name. Separate namespaces let the same name be used safely in different parts of a program.
Example
course = "Python"
level = "Beginner"
print(course)
print(level)
Output
Python
Beginner
Output explanation: The global namespace stores the names course and level with their string objects. Python looks up each name and prints its associated value.
14.14 The globals() Function
The globals() function returns a dictionary representing the current global namespace. Its keys are global names, and its values are the objects connected to those names. This function can help with learning and debugging, but regular programs should usually access known variables directly rather than changing the global namespace dictionary.
Example
city = "Toronto"
global_names = globals()
print(global_names["city"])
Output
Toronto
Output explanation: The global namespace contains the name city. globals() returns the namespace dictionary, and looking up the key city produces and prints Toronto.
14.15 The locals() Function
The locals() function returns a dictionary showing names in the current local namespace. Inside a function, it can display the function's parameters and local variables. It is useful for inspection and debugging. Beginners should not rely on changing this dictionary because updates may not change the actual local variables reliably.
Example
def show_details():
name = "Omar"
age = 18
details = locals()
print(details["name"])
print(details["age"])
show_details()
Output
Omar
18
Output explanation: Inside the function, locals() includes the local variables name and age. The program retrieves their values from the dictionary and prints them.
14.16 Name Resolution
Name resolution is the process Python uses to decide which object a name refers to. Python follows the LEGB order and raises a NameError when it cannot find the name anywhere. Understanding name resolution helps beginners diagnose errors and understand why a nearby variable is chosen instead of another variable with the same spelling.
Example
language = "Python"
def show_language():
print(language)
show_language()
Output
Python
Output explanation: The function has no local variable called language, so Python continues searching. It finds the name in global scope and prints its value.
14.17 Object Lifetime
Object lifetime describes how long an object remains available in memory. An object is created when Python evaluates a value, and it usually remains alive while something still refers to it. When no references remain, Python may remove the object automatically. Scope and lifetime are related, but they are not exactly the same concept.
Example
def create_message():
message = "Temporary text"
print(message)
create_message()
Output
Temporary text
Output explanation: The string object is referenced by the local variable message while the function runs. The function prints it. After the function ends, that local name disappears and the object may be cleaned up if no other reference exists.
14.18 Garbage Collection Introduction
Garbage collection is Python's automatic system for reclaiming memory used by objects that are no longer needed. Python mainly tracks references and can also detect certain groups of objects that reference one another. Beginners normally do not need to free memory manually, but understanding this idea explains why unused objects do not stay in memory forever.
Example
items = ["book", "pen"]
print(items)
items = None
print(items)
Output
['book', 'pen']
None
Output explanation: The variable first refers to a list, so the list is printed. It is then reassigned to None. If no other reference points to the old list, Python can later reclaim its memory.
14.19 Avoiding Global Variables
Avoiding unnecessary global variables makes programs easier to test, understand, and reuse. Instead of letting a function secretly read or change shared data, pass values into the function as parameters and return the result. This creates a clear flow of information and reduces the chance that one function unexpectedly changes another part of the program.
Example
def increase_score(current_score):
return current_score + 1
score = 5
score = increase_score(score)
print(score)
Output
6
Output explanation: The function receives the current score as a parameter and returns a new value. The main program stores that result, so the score becomes 6 without using the global keyword.
14.20 Scope Best Practices
Good scope practices include keeping variables as local as possible, using clear names, passing information through parameters, returning results, and avoiding unnecessary global changes. Small functions with limited responsibility are easier to understand. Constants may be global when appropriate, but changing shared global data should be kept to a minimum.
Example
DISCOUNT_RATE = 0.10
def discounted_price(price, rate):
return price - price * rate
final_price = discounted_price(80, DISCOUNT_RATE)
print(final_price)
Output
72.0
Output explanation: The global constant supplies a fixed discount rate, while the function receives all information through parameters and returns its result. Ten percent is removed from 80, producing 72.0.
14.21 Chapter Practice Exercises
Practice exercises help you test whether you understand local, enclosing, global, and built-in scope. Work through each task slowly, predict the output before running the code, and explain which scope provides every name. Practice should include functions, nested functions, shadowing, global and nonlocal keywords, and the globals() and locals() inspection functions.
Example
number = 10
def double_number(value):
result = value * 2
return result
print(double_number(number))
Output
20
Output explanation: The global variable number is passed into the function as the local parameter value. The local variable result stores 20, and the returned value is printed.
14.22 Chapter Mini Project
This mini project builds a simple bank balance tracker to practise scope safely. A function receives the current balance and a deposit amount, creates local calculation variables, and returns the updated balance. The project avoids changing a global balance inside the function, making the data flow clear and easier for a beginner to test.
Example
def deposit(current_balance, amount):
new_balance = current_balance + amount
return new_balance
balance = 100
balance = deposit(balance, 50)
print("New balance:", balance)
Output
New balance: 150
Output explanation: The global variable balance starts at 100 and is passed into the function. The function creates the local variable new_balance, returns 150, and the main program stores and prints the updated balance.