Blog Post #97: Modifying the Outside World: The global Keyword

In Post #96, we ran into a puzzle. When we tried to change a global variable from inside a function, we instead created a new “shadow” local variable, and the original global variable remained untouched. This is Python’s default behavior, designed to protect your global scope from accidental changes by functions.

But what if you genuinely want to modify a global variable from inside a function? How do you tell Python your explicit intention?

The answer is the global keyword. In this post, we’ll learn how to use it, and just as importantly, discuss why it should be used with caution.

Announcing Your Intent with global

The global keyword is a declaration. It’s a statement you make inside a function that tells Python: “For the variable name that follows, I’m not creating a new local variable. I am referring to the one that already exists in the global scope.”

The syntax is simple. This line must appear inside your function before you use or assign a value to that variable.

global variable_name

An Example: Modifying a Global Variable

Let’s fix our level_up function from the previous post. By adding global player_level at the start of the function, we are telling it to modify the global variable directly instead of creating a new local one.

player_level = 10 # Global variable

def level_up_global():
    # Tell Python we want to modify the GLOBAL player_level
    global player_level
    
    player_level += 1
    print(f"Inside the function, the player is now level: {player_level}")

print(f"Before the call, the global player level is: {player_level}")
level_up_global()
print(f"After the call, the global player level has been changed to: {player_level}")

The output now shows that the global variable has been successfully modified:

Before the call, the global player level is: 10
Inside the function, the player is now level: 11
After the call, the a global player level has been changed to: 11

A Strong Word of Caution: Use global Sparingly

While the global keyword works, it is generally considered bad practice in modern Python programming and should be avoided whenever possible. Using it can lead to code that is difficult to read, debug, and maintain.

Here’s why:

  • It breaks function encapsulation: A well-designed function is a self-contained “black box.” It receives data through parameters and sends data out through return. Relying on a global variable breaks this; the function now has a hidden dependency on the outside world.
  • It creates “side effects”: A function call can now secretly change the state of your program in unexpected ways. This makes it much harder to reason about your code and find bugs.
  • It reduces reusability: You can’t easily copy a function that relies on global variables to another project, because that project would also need to have those exact global variables defined.

The Better Alternative: Parameters and Return Values

So, what should you do instead? The “Pythonic” way is to make your functions pure and predictable by passing data in as arguments and getting results back with return.

Let’s rewrite our level_up logic the right way.

def level_up_clean(current_level):
    """Takes a level, returns the level incremented by 1."""
    return current_level + 1

player_level = 10
print(f"Level before: {player_level}")

# The change is explicit and easy to understand
player_level = level_up_clean(player_level)

print(f"Level after: {player_level}")

This level_up_clean function is perfect. It’s completely self-contained, has no hidden side effects, is easy to test, and is fully reusable. The main part of our script remains in control of the player_level variable.

What’s Next?

The global keyword allows you to modify global variables from within a function, but it’s a tool that should be used rarely, if ever. Prefer passing data via parameters and returning values to keep your functions clean, predictable, and maintainable.

We’ve now talked about local scope and global scope. But how does Python decide which variable to use when a name exists in multiple scopes? There is a clear set of rules it follows. In Post #98, we will demystify this process by learning about the LEGB rule.

Author

Debjeet Bhowmik

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com

Leave a Comment