As you start writing more complex Python programs, you'll encounter a concept called 'scope.' Scope dictates where in your code a particular variable is accessible. Think of it like a set of rules that determines visibility. Understanding scope is crucial for preventing unexpected errors and writing cleaner, more manageable code. Python has two primary types of scope: local and global.
A variable defined inside a function has local scope. This means it can only be accessed from within that specific function. Once the function finishes executing, the local variables are destroyed. This is a good thing because it prevents variables in one function from accidentally interfering with variables in another.
def greet():
message = "Hello from inside the function!"
print(message)
greet() # This works fine
# print(message) # This would cause a NameError!In the example above, message is a local variable to the greet() function. We can print it inside greet(), but trying to access it outside the function will result in a NameError because it no longer exists.
Variables defined outside of any function, at the top level of your script, have global scope. These variables can be accessed from anywhere in your program, both inside and outside of functions.
global_variable = "I am a global variable."
def display_global():
print(global_variable)
print(global_variable) # Accessible here
display_global() # Accessible inside the functionHere, global_variable is defined at the module level, making it accessible anywhere.
By default, when you assign a value to a variable inside a function, Python assumes you are creating a new local variable, even if a global variable with the same name already exists. To actually modify a global variable from within a function, you need to explicitly tell Python using the global keyword.
counter = 0
def increment_counter():
global counter # Declare intent to modify the global 'counter'
counter += 1
print(f"Inside function: {counter}")
print(f"Before calling function: {counter}")
increment_counter()
print(f"After calling function: {counter}")Without the global counter line, the assignment counter += 1 would have created a new local counter that would disappear after the function call, leaving the original global counter unchanged.
Python follows a specific order when looking for a variable: the LEGB rule:
- Local: The innermost scope, within the current function.
- Enclosing function locals: For nested functions, this refers to the scopes of any outer functions.
- Global: The module-level scope.
- Built-in: Names preassigned in Python's built-in module (like
print,len,sum, etc.).
Python searches for a variable in this order. As soon as it finds the variable, it stops searching.
graph TD;
A(Start Search) --> B(Local Scope);
B -- Not Found --> C(Enclosing Function Locals);
C -- Not Found --> D(Global Scope);
D -- Not Found --> E(Built-in Scope);
E -- Not Found --> F(NameError!);
While you can modify global variables, it's often a good practice to limit their use, especially in larger projects. Excessive modification of global variables can make it harder to reason about your code and track down bugs. Prefer passing variables as arguments to functions and returning values. This makes the data flow explicit and the functions more self-contained and reusable.