Mastering Python Global Variables: Best Practices for Secure Coding
Mastering Python Global Variables: Best Practices for Secure Coding

Make Script-Level Variables Private in Python

Learn best practices for managing Python global variables—use encapsulation, naming conventions, and classes for security.7 min


When writing Python scripts, it’s common to declare variables at the script level, making them accessible throughout the script. These are often called global variables, and they’re handy for sharing data between functions. But what happens when other scripts import your module and access those global variables without constraints? That can quickly lead to messy code, difficult debugging, or unintended side effects.

Declaring Script-Level Variables in Python

Global variables are declared at the script level outside any function, making them accessible throughout your script. For example:

# script.py
username = "admin"
password = "1234"

def login(user, pwd):
    if user == username and pwd == password:
        print("Welcome!")
    else:
        print("Access Denied.")

In this case, username and password are script-level (global) variables, accessible inside functions without explicitly declaring them with the global keyword. The keyword global comes into play only when you want to modify a global variable within a local function scope.

The Problem: Global Variables Accessible From Anywhere

Global variables might look convenient, but too many can spell chaos. Imagine importing this script from another Python file:

# external_script.py
import script

print(script.password)  # Outputs: "1234" (this may be unintended!)

Now this external script has full access to your variables, potentially exposing sensitive data or causing unintended side effects.

Understanding Encapsulation and Privacy in Python

Python provides mechanisms—though not strict—to encapsulate or hide script-level variables, making them less prone to misuse. Encapsulation means bundling data and methods in a restricted scope, allowing controlled interactions only.

Unlike languages like Java or C#, Python does not strictly enforce private variables. Instead, Python follows the principle of “consenting adults,” assuming developers will responsibly access and update variables.

Using Class Properties to Create Private Variables

One practical way to hide variables is encapsulation using Python classes. Variables defined inside classes can be made easily private using naming conventions:

class Account:
    def __init__(self, username, password):
        self.__username = username  # Private variable
        self.__password = password  # Private variable

    def authenticate(self, user, pwd):
        return user == self.__username and pwd == self.__password

account = Account("user123", "securepwd")
print(account.authenticate("user123", "securepwd"))  # True

Here, variables prefixed with double underscores (__) are called private. Although Python doesn’t completely block external access, it employs a mechanism called name mangling to make these variables difficult (but not impossible) to access externally.

If you attempt to access them directly, Python guards them by changing the name internally:

print(account.__password)  # AttributeError
print(account._Account__password)  # Outputs: "securepwd" (possible but harder!)

Techniques to Hide Script-Level Variables from Other Scripts

Apart from classes, there are other powerful techniques to better hide variables, keeping your module tidy and secure.

1. Using Decorators to Restrict Access

Python decorators can help restrict access to functions or variables. They can wrap around functions, checking permissions or states before providing access.

While decorators are not typically used directly on variables, they can protect sensitive methods that interact with confidential variables, providing indirect encapsulation.

2. Naming Conventions with Single Underscore

Simple and widely practiced, using single underscore naming conventions clearly communicates that variables or functions are meant to be “protected” or internal-use:

# credentials.py

_username = "privateuser"
_password = "secretpwd"

When importing from another script, Python programmers understand not to access _username or _password, though technically Python allows the access. It’s a strong convention respected community-wide.

3. Name Mangling to Create Private Variables

As mentioned, double underscores (__) invoke Python’s built-in name mangling:

# variables.py
__secret_key = "hidden-value"

def print_key():
    print(__secret_key)

Attempting to directly import and use __secret_key from another Python file triggers an error:

# importer_script.py
from variables import __secret_key  # This fails with ImportError

You’d have to know exactly how Python mangles it (via _variables__secret_key) to access it—complicating unwanted usage nicely.

Comparison to C’s Static Module Variables

A relevant parallel for programmers familiar with languages like C is the concept of static module variables. By declaring C variables as static at the module level, you restrict their visibility only to that module. Python’s private naming conventions effectively offer a similar mechanism, signaling intentional encapsulation.

However, the main difference is strictness. C’s static variables are enforced by the compiler, strictly inaccessible externally. Python, contrastingly, operates by community standards, relying on responsible usage over strict limitations.

Implementing and Testing Script-Level Private Variables

Let’s look at a practical example by creating a Python script named config.py which holds private configuration variables:

# config.py
_api_key = "234jhbS43fkhbwe334"  # Intended to be private

Import this in another script, and test the visibility:

# main_script.py
import config

print(config._api_key)  # Accessible but conventionally should not do this!

To enforce more substantial privacy, encapsulate it within a class with double underscores:

# secure_config.py
class Config:
    def __init__(self):
        self.__api_key = "safekey123"

    def get_key(self):
        return self.__api_key

When testing this setup:

# import_secure.py
from secure_config import Config

conf = Config()
print(conf.get_key())  # Outputs: safekey123
print(conf.__api_key)  # Raises AttributeError

Best Practices for Managing Script-Level Variables

To effectively manage your script-level variables and maintain readable, clean Python code, keep these best practices in mind:

  1. Minimize global variable usage: Limit global variables to reduce complexity and unintended effects.
  2. Use clear naming conventions: Underscores help other developers understand variable scopes intuitively.
  3. Create meaningful documentation: Clearly document what is accessible externally and what’s internal-use-only.

For more guidelines, check out the official Python documentation on private variables and encapsulation.

Potential Issues with Private Variables in Python Scripts

Though useful, private variables carry their own challenges:

  • Debugging complexity: Private variables can complicate debugging efforts, as inaccessible external access adds layers of complexity.
  • Reduced readability: Excessively using private variables without good reason reduces code transparency and readability.
  • Limited protection: Python privacy conventions rely on programmer collaboration and responsibility rather than strict protection.

Keep these potential issues in mind when structuring scripts.

Protecting your script-level variables isn’t just good practice—it’s essential to keep your Python code maintainable, readable, and organized. While Python doesn’t enforce pure privacy strictly, conscientious usage and proper naming conventions go a long way toward making your code secure and maintainable.

If you’re interested in a deeper dive into similar Python scope topics, explore more articles within our Python resources category. Have an experience or practice around script-level variables you’d like to share? Let us know in the comments below!


Like it? Share with your friends!

Shivateja Keerthi
Hey there! I'm Shivateja Keerthi, a full-stack developer who loves diving deep into code, fixing tricky bugs, and figuring out why things break. I mainly work with JavaScript and Python, and I enjoy sharing everything I learn - especially about debugging, troubleshooting errors, and making development smoother. If you've ever struggled with weird bugs or just want to get better at coding, you're in the right place. Through my blog, I share tips, solutions, and insights to help you code smarter and debug faster. Let’s make coding less frustrating and more fun! My LinkedIn Follow Me on X

0 Comments

Your email address will not be published. Required fields are marked *