How to Check if a Variable Exists in Python
In Python, variables are created dynamically when you assign a value to them, there's no explicit declaration step. This flexibility means that trying to access a variable that hasn't been defined yet raises a NameError, which can crash your program unexpectedly.
Checking whether a variable exists before using it is a common need in scenarios like conditional initialization, dynamic code execution, configuration handling, and debugging. In this guide, you'll learn multiple reliable methods to check if a variable exists in Python, covering both local and global scopes.
Understanding the Problem
When you access a variable that hasn't been defined, Python raises a NameError:
print(username)
Output:
NameError: name 'username' is not defined
The goal is to detect whether a variable exists before accessing it, so you can handle the missing case gracefully instead of letting your program crash.
Using a Try-Except Block
The most Pythonic way to check if a variable exists is to simply try accessing it and catch the NameError if it doesn't exist. This follows Python's EAFP (Easier to Ask Forgiveness than Permission) philosophy.
try:
username
print(f"Variable exists with value: {username}")
except NameError:
print("Variable 'username' does not exist.")
Output:
Variable 'username' does not exist.
Now, if the variable is defined:
username = "Alice"
try:
username
print(f"Variable exists with value: {username}")
except NameError:
print("Variable 'username' does not exist.")
Output:
Variable exists with value: Alice
The try-except approach is the recommended method in most situations. It's clean, handles edge cases naturally, and doesn't require you to know whether the variable is local or global.
Using locals()
The locals() function returns a dictionary of all variables defined in the current local scope. You can check if a variable name exists as a key in this dictionary.
def greet():
name = "Alice"
if 'name' in locals():
print(f"Variable exists: name = {name}")
else:
print("Variable 'name' does not exist in local scope.")
greet()
Output:
Variable exists: name = Alice
This method is particularly useful inside functions where you want to verify that a local variable has been assigned before using it.
Checking for a Variable That Doesn't Exist Locally
def greet():
if 'name' in locals():
print(f"name = {name}")
else:
print("Variable 'name' is not defined locally.")
greet()
Output:
Variable 'name' is not defined locally.
Using globals()
The globals() function returns a dictionary of all variables in the global (module-level) scope. Use it when you need to check for variables defined outside of functions and classes.
app_name = "MyApp"
def check_config():
if 'app_name' in globals():
print(f"Global variable found: app_name = {app_name}")
else:
print("Global variable 'app_name' is not defined.")
check_config()
Output:
Global variable found: app_name = MyApp
This is especially useful when functions depend on global configuration variables that may or may not have been set:
def check_config():
if 'debug_mode' in globals():
print(f"Debug mode: {debug_mode}")
else:
print("'debug_mode' is not configured. Using default: False")
check_config()
Output:
'debug_mode' is not configured. Using default: False
Combining locals() and globals()
When you're unsure whether a variable lives in the local or global scope, check both:
threshold = 100 # Global variable
def process():
limit = 50 # Local variable
for var_name in ['limit', 'threshold', 'missing_var']:
if var_name in locals() or var_name in globals():
print(f"'{var_name}' exists.")
else:
print(f"'{var_name}' does NOT exist.")
process()
Output:
'limit' exists.
'threshold' exists.
'missing_var' does NOT exist.
Checking for Object Attributes with hasattr()
If you need to check whether an attribute exists on an object (rather than a standalone variable), use the built-in hasattr() function:
class User:
def __init__(self, name):
self.name = name
user = User("Alice")
print(hasattr(user, 'name')) # True
print(hasattr(user, 'email')) # False
Output:
True
False
This is commonly used when working with objects that might have optional attributes:
class Config:
def __init__(self):
self.host = "localhost"
config = Config()
if hasattr(config, 'port'):
print(f"Port: {config.port}")
else:
print("Port not configured. Using default: 8080")
Output:
Port not configured. Using default: 8080
- Use
locals()/globals()/try-exceptfor standalone variables. - Use
hasattr()for attributes on objects, classes, or modules.
import math
# Checking a module attribute
print(hasattr(math, 'pi')) # True
print(hasattr(math, 'tau')) # True
print(hasattr(math, 'golden')) # False
Practical Example: Safe Variable Initialization
A common real-world pattern is initializing a variable only if it doesn't already exist. It is useful for counters, caches, or configuration defaults:
# Initialize 'counter' only if it hasn't been set
try:
counter
except NameError:
counter = 0
counter += 1
print(f"Counter: {counter}")
Output (first run):
Counter: 1
An alternative using globals():
if 'counter' not in globals():
counter = 0
counter += 1
print(f"Counter: {counter}")
Quick Comparison of Methods
| Method | Scope | Best For | Pythonic |
|---|---|---|---|
try / except NameError | Any scope | General-purpose checks | ✅ Most Pythonic |
'var' in locals() | Local scope | Checking inside functions | ✅ Good |
'var' in globals() | Global scope | Module-level variables | ✅ Good |
locals() + globals() | Both scopes | When scope is uncertain | ✅ Good |
hasattr(obj, 'attr') | Object attributes | Checking object/class/module attributes | ✅ Good |
Conclusion
Python provides several reliable ways to check if a variable exists:
try/except NameErroris the most Pythonic and versatile approach. It works regardless of scope and follows Python's EAFP philosophy.locals()andglobals()let you inspect specific scopes by checking if a variable name exists in their respective dictionaries.hasattr()is the right tool when checking for attributes on objects, classes, or modules.
For most situations, the try-except block is the cleanest choice. It keeps your code readable, handles edge cases naturally, and doesn't require you to think about which scope the variable belongs to.