In programming, the term constant refers to names representing values that don’t change during a program’s execution. Constants are a fundamental concept in programming, and Python developers use them in many cases. However, Python doesn’t have a dedicated syntax for defining constants. In practice, Python constants are just variables that never change.
To prevent programmers from reassigning a name that’s supposed to hold a constant, the Python community has adopted a naming convention: use uppercase letters. For every Pythonista, it’s essential to know what constants are, as well as why and when to use them.
In this tutorial, you’ll learn how to:
- Properly define constants in Python
- Identify some built-in constants
- Use constants to improve your code’s readability, reusability, and maintainability
- Apply different approaches to organize and manage constants in a project
- Use several techniques to make constants strictly constant in Python
By learning to define and use constants, you’ll dramatically improve your code’s readability, maintainability, and reusability.
To learn the most from this tutorial, you’ll need basic knowledge of Python variables, functions, modules, packages, and namespaces. You’ll also need to know the basics of object-oriented programming in Python.
Sample Code: Click here to download sample code that shows you how to use constants in Python.
Understanding Constants and Variables
Variables and constants are two historical and fundamental concepts in computer programming. Most programming languages use these concepts to manipulate data and work in an effective and logical fashion.
Variables and constants will probably be present in each project, app, library, or other piece of code that you’ll ever write. The question is: what are variables and constants in practice?
What Variables Are
In math, a variable is defined as a symbol that refers to a value or quantity that can change over time. In programming, a variable is also a symbol or name typically associated with a memory address containing a value, object, or piece of data. Like in math, the content of a programming variable can change during the execution of the code that defines it.
Variables typically have a descriptive name that’s somehow associated with a target value or object. This target value can be of any data type. So, you can use variables to represent numbers, strings, sequences, custom objects, and more.
You can perform two main operations on a variable:
- Access its value
- Assign it a new value
In most programming languages, you can access the value associated with a variable by citing the variable’s name in your code. To assign a new value to a given variable, you’ll use an assignment statement, which often consists of the variable’s name, an assignment operator, and the desired value.
In practice, you’ll find many examples of magnitudes, data, and objects that you can represent as variables. A few examples include temperature, speed, time, and length. Other examples of data that you can treat as variables include the number of registered users in a web app, the number of active characters in a video game, and the number of miles covered by a runner.
What Constants Are
Math also has the concept of constants. The term refers to a value or quantity that never changes. In programming, constants refer to names associated with values that never change during a program’s execution.
Just like variables, programming constants consist of two things: a name and an associated value. The name will clearly describe what the constant is all about. The value is the concrete expression of the constant itself.
Like with variables, the value associated with a given constant can be of any of data type. So, you can define integer constants, floating-point constants, character constants, string constants, and more.
After you’ve defined a constant, it’ll only allow you to perform a single operation on it. You can only access the constant’s value but not change it over time. This is different from a variable, which allows you to access its value, but also reassign it.
You’ll use constants to represent values that won’t change. You’ll find lots of these values in your day-to-day programming. A few examples include the speed of light, the number of minutes in an hour, and the name of a project’s root folder.
Why Use Constants
In most programming languages, constants protect you from accidentally changing their values somewhere in the code when you’re coding at two in the morning, causing unexpected and hard-to-debug errors. Constants also help you make your code more readable and maintainable.
Some advantages of using constants instead of using their values directly in your code include:
| Advantage | Description |
|---|---|
| Improved readability | A descriptive name representing a given value throughout a program is always more readable and explicit than the bare-bones value itself. For example, it’s easier to read and understand a constant named MAX_SPEED than the concrete speed value itself. |
| Clear communication of intent | Most people will assume that 3.14 may refer to the Pi constant. However, using the Pi, pi, or PI name will communicate your intent more clearly than using the value directly. This practice will allow other developers to understand your code quickly and accurately. |
| Better maintainability | Constants enable you to use the same name to identify the same value throughout your code. If you need to update the constant’s value, then you don’t have to change every instance of the value. You just have to change the value in a single place: the constant definition. This improves your code’s maintainability. |
| Lower risk of errors | A constant representing a given value throughout a program is less error-prone than several explicit instances of the value. Say that you use different precision levels for Pi depending on your target calculations. You’ve explicitly used the values with the required precision for every calculation. If you need to change the precision in a set of calculations, then replacing the values can be error-prone because you can end up changing the wrong values. It’s safer to create different constants for different precision levels and change the code in a single place. |
| Reduced debugging needs | Constants will remain unchanged during the program’s lifetime. Because they’ll always have the same value, they shouldn’t cause errors and bugs. This feature may not be necessary in small projects, but it may be crucial in large projects with multiple developers. Developers won’t have to invest time debugging the current value of any constant. |
| Thread-safe data storage | Constants can only be accessed, not written. This feature makes them thread-safe objects, which means that several threads can simultaneously use a constant without the risk of corrupting or losing the underlying data. |
As you’ve learned in this table, constants are an important concept in programming for good reason. They can make your life more pleasant and your code more reliable, maintainable, and readable. Now, when should you use constants?
When Use Constants
Life, and particularly science, is full of examples of constant values, or values that never change. A few examples include:
- 3.141592653589793: A constant denoted by π, spelled as Pi in English, which represents the ratio of a circle’s circumference to its diameter
- 2.718281828459045: A constant denoted by e and known as Euler’s number, which is closely related to the natural logarithm and compound interest
- 3,600: The number of seconds in one hour, which is considered constant in most applications, even though leap seconds sometimes are added to account for variability in the Earth’s rotation speed
- -273.15: A constant representing absolute zero in degrees Celsius, which is equal to 0 kelvins on the Kelvin temperature scale
All the above examples are constant values that people commonly use in life and science. In programming, you’ll often find yourself dealing with these and many other similar values that you can consider and treat as constants.
In summary, use a constant to represent a quantity, magnitude, object, parameter, or any other piece of data that’s supposed to remain unchanged during its lifetime.
Defining Your Own Constants in Python
Up to this point, you’ve learned about constants as a general concept in life, science, and programming. Now it’s time to learn how Python deals with constants. First, you should know that Python doesn’t have a dedicated syntax for defining constants.
In other words, Python doesn’t have constants in the strict sense of the word. It only has variables, primarily because of its dynamic nature. Therefore, to have a constant in Python, you need to define a variable that never changes and stick to that behavior by avoiding assignment operations on the variable itself.
Note: In this section, you’ll focus on defining your own constants. However, there are a few constants that are built into Python. You’ll learn about them later on.
Then, how would Python developers know that a given variable represents a constant? The Python community has decided to use a strong naming convention to distinguish between variables and constants. Keep reading to learn more!
User-Defined Constants
To tell other programmers that a given value should be treated as a constant, you must use a widely accepted naming convention for the constant’s identifier or name. You should write the name in capital letters with underscores separating words, as stated in the Constants section of PEP 8.
Here are a few example of user-defined Python constants:
PI = 3.14
MAX_SPEED = 300
DEFAULT_COLOR = "\033[1;34m"
WIDTH = 20
API_TOKEN = "593086396372"
BASE_URL = "https://api.example.com"
DEFAULT_TIMEOUT = 5
ALLOWED_BUILTINS = ("sum", "max", "min", "abs")
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
...
]
Note that you’ve created these constants exactly as you’d create variables. You’ve used a descriptive name, the assignment operator (=), and the constant’s specific value.
By using capital letters only, you’re communicating that the current name is intended to be treated as a constant—or more precisely, as a variable that never changes. So, other Python developers will know that and hopefully won’t perform any assignment operation on the variable at hand.
Note: Again, Python doesn’t support constants or non-reassignable names. Using uppercase letters is just a convention, and it doesn’t prevent developers from assigning new values to your constant. So, any programmer working on your code needs to be careful and never write code that changes the values of constants. Remember this rule because you also need to follow it.
Because Python constants are just variables, both follow similar naming rules, with the only distinction being that constants use uppercase letters only. Following this idea, constants’ names can:
- Be of any length
- Consist of uppercase letters (
A–Z) - Include digits (
0–9) but not as their first character - Use underscore characters (
_) to separate words or as their first character
Using uppercase letters makes your constants stand out from your variables. This way, other developers will unambiguously recognize their purpose.
As a general naming recommendation, avoid abbreviated names when defining constants. The purpose of a constant’s name is to clarify the meaning of the constant’s value so that you can reuse it later. This goal demands descriptive names. Avoid using single-letter names, uncommon abbreviations, and generic names like NUMBER or MAGNITUDE.
The recommended practice is to define constants at the top of any .py file right after any import statements. This way, people reading your code will immediately know the constants’ purpose and expected treatment.
Module-Level Dunder Constants
Module-level dunder names are special names that start and end with a double underscore. Some examples include names such as __all__, __author__, and __version__. These names are typically treated as constants in Python projects.
Note: In Python, a dunder name is a name with special meaning. It starts and ends in double underscores, and the word dunder is a portmanteau of double underscore.
According to Python’s coding style guide, PEP 8, module-level dunder names should appear after the module’s docstring and before any import statement except for __future__ imports.
Here’s a sample module that includes a bunch of dunder names:
# greeting.py
"""This module defines some module-level dunder names."""
from __future__ import barry_as_FLUFL
__all__ = ["greet"]
__author__ = "Real Python"
__version__ = "0.1.0"
import sys
def greet(name="World"):
print(f"Hello, {name}!")
print(f"Greetings from version: {__version__}!")
print(f"Yours, {__author__}!")
In this example, __all__ defines up front the list of names that Python will import when you use the from module import * import construct in your code. In this case, someone importing greeting with a wildcard import will just get the greet() function back. They won’t have access to __author__, __version__, and other names not listed on __all__.
Note: The from module import * construct allows you to import all the names defined in a given module in one go. The __all__ attribute restricts the imported names to only those in the underlying list.
The Python community strongly discourages this import construct, commonly known as wildcard imports, because it tends to clutter your current namespace with names that you probably won’t use in your code.
In contrast, __author__ and __version__ have meaning only for the code’s authors and users rather than for the code’s logic itself. These names should be treated as constants since no code should be allowed to change the author or version during the program’s execution.
Note that the greet() function does access the dunder names but doesn’t change them. Here’s how greet() works in practice:
>>> from greeting import *
>>> greet()
Hello, World!
Greetings from version: 0.1.0!
Yours, Real Python!
In general, there are no hard rules that prevent you from defining your own module-level dunder names. However, the Python documentation strongly warns against using dunder names other than those generally accepted and used by the community. The core developers may introduce new dunder names to the language in the future without any warning.
Putting Constants Into Action
So far, you’ve learned about constants and their role and importance in programming. You’ve also learned that Python doesn’t support strict constants. That’s why you can think of constants as variables that never change.
In the following sections, you’ll code examples of how valuable constants can be in your day-to-day coding adventure.
Replacing Magic Numbers for Readability
In programming, the term magic number refers to any number that appears directly in your code without any explanation. It’s a value that comes out of the blue, making your code enigmatic and difficult to understand. Magic numbers also makes programs less readable and more difficult to maintain and update.
For example, say you have the following function:
def compute_net_salary(hours):
return hours * 35 * (1 - (0.04 + 0.1))
Can you tell up front what the meaning of each number in this computation is? Probably not. The different numbers in this function are magic numbers because you can’t reliably infer their meanings from the numbers themselves.
Check out the following refactored version of this function:
HOURLY_SALARY = 35
SOCIAL_SECURITY_TAX_RATE = 0.04
FEDERAL_TAX_RATE = 0.10
def compute_net_salary(hours):
return (
hours
* HOURLY_SALARY
* (1 - (SOCIAL_SECURITY_TAX_RATE + FEDERAL_TAX_RATE))
)
With these minor updates, your function now reads like a charm. You and any other developers reading your code can surely tell what this function does because you’ve replaced the original magic numbers with appropriately named constants. The name of each constant clearly explains its corresponding meaning.
Every time you find yourself using a magic number, take the time to replace it with a constant. This constant’s name must be descriptive and unambiguously explain the meaning of the target magic number. This practice will automatically improve the readability of your code.
Reusing Objects for Maintainability
Another everyday use case of constants is when you have a given value repeatedly appearing in different parts of your code. If you insert the concrete value into the code at every required place, then you’ll be in trouble if you ever need to change the value for any reason. In this situation, you’ll need to change the value in every place.
Changing the target value in multiple places at a time is error-prone. Even if you rely on your editor’s Find and Replace feature, you can leave some unchanged instances of the value, which can lead to unexpected bugs and weird behaviors later.
To prevent these annoying issues, you can replace the value with a properly named constant. This will allow you to set the value once and repeat it in as many locations as needed. If you ever need to change the constant’s value, then you just have to change it in a single place: the constant definition.
For example, say you’re writing a Circle class, and you need methods to compute the circle’s area, perimeter, and so on. After a few coding minutes, you end up with the following class:
# circle.py
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius**2
def perimeter(self):
return 2 * 3.14 * self.radius
def projected_volume(self):
return 4/3 * 3.14 * self.radius**3
def __repr__(self):
return f"{self.__class__.__name__}(radius={self.radius})"
This example uncovers how the approximate value of Pi (3.14) has been written as a magic number in several methods of your Circle class. Why is this practice a problem? Say you need to increase the precision of Pi. Then you’ll have to manually change the value in at least three different places, which is tedious and error-prone, making your code difficult to maintain.
Note: Generally, you don’t need to define Pi yourself. Python ships with some built-in constants, including Pi. You’ll see how to take advantage of it later.
Using a named constant to store the value of Pi is an excellent approach to solving these issues. Here’s an enhanced version of the above code:
# circle.py
PI = 3.14
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return PI * self.radius**2
def perimeter(self):
return 2 * PI * self.radius
def projected_volume(self):
return 4/3 * PI * self.radius**3
def __repr__(self):
return f"{self.__class__.__name__}(radius={self.radius})"
This version of Circle uses the global constant PI to replace the magic number. This code has several advantages compared to the original code. If you need to increase the precision of Pi, then you just have to update the PI constant’s value at the beginning of the file. This update will immediately reflect on the rest of the code without requiring any additional action on your side.
Note: Constants shouldn’t change during your code’s execution. However, during development, you can change and tweak your constants according to your needs. Updating the precision of Pi in your Circle class is a good example of why you may need to change the value of a constant during the development of your code.
Another advantage is that now your code is more readable and easier to understand. The constant’s name is self-explanatory and reflects the accepted math terminology.
Declaring a constant once and then reusing it several times, as you did in the above example, represents a significant maintainability improvement. If you ever have to update the constant’s value, then you’ll update it a single place rather than in multiple places, which implies way less effort and error risk.
Providing Default Argument Values
Using named constants to provide default argument values to functions, methods, and classes is another common practice in Python. There are lots of examples of this practice in the Python standard library.
For example, the zipfile module provides tools to create, read, write, append, and list ZIP files. The most relevant class in this module is ZipFile. With ZipFile, you can manipulate your ZIP files efficiently and quickly.
The class constructor of ZipFile takes an argument called compression, which allows you to select among a few available data compression methods. This argument is optional and has ZIP_STORED as its default value, meaning that ZipFile doesn’t compress the input data by default.
In this example, ZIP_STORED is a constant defined in zipfile. The constant holds a numeric value for uncompressed data. You’ll also find other compression methods represented by named constants like ZIP_DEFLATED for the Deflate compression algorithm, for example.
The compression argument in the ZipFile class constructor is a good example of using constants to provide default argument values when you have an argument that can take only a limited number of valid values.
Another example of when constants come in handy as default argument values is when you have several functions with a recurrent argument. Say that you’re developing an application that connects to a local SQLite database. Your app uses the following set of functions to manage the database:
import sqlite3
from sqlite3 import Error
def create_database(db_path):
# Code to create the initial database goes here...
def create_connection(db_path):
# Code to create a database connection goes here...
def backup_database(db_path):
# Code to back up the database goes here...
These functions perform different actions on your SQLite database. Note that all your functions share the db_path argument.
While you’re developing the application, you decide to provide a default database path to your functions so that you can quickly test them. In this case, you can directly use the path as a default value to the db_path argument.
However, it’s better to use a named constant to provide the default database path:
import sqlite3
from sqlite3 import Error
DEFAULT_DB_PATH = "/path/to/database.sqlite"
def create_database(db_path=DEFAULT_DB_PATH):
# Code to create the initial database goes here...
def create_connection(db_path=DEFAULT_DB_PATH):
# Code to create a database connection goes here...
def backup_database(db_path=DEFAULT_DB_PATH):
# Code to back up the database goes here...
This small update enables you to quickly test your app by targeting a sample database during development. It also improves the maintainability of your code because you can reuse this constant in other database-related functions that appear in future versions of your app.
Finally, you’ll find situations in which you want to pass an object with certain behavior to a class, method, or function. This practice is typically known as duck typing and is a fundamental principle in Python. Now say that your code will take care of providing a standard implementation of the required object. If your users want a custom object, then they should provide it themselves.
In this situation, you can use a constant to define the default object and then pass this constant as a default argument value to the target class, method, or function. Check out the following example of a hypothetical FileReader class:
# file_handler.py
from readers import DEFAULT_READER
class FileHandler:
def __init__(self, file, reader=DEFAULT_READER):
self._file = file
self._reader = reader
def read(self):
self._reader.read(self._file)
# FileHandler implementation goes here...
This class provides a way to manipulate different types of files. The .read() method uses the injected reader object to read the input file according to its specific format.
Here’s a toy implementation of a reader class:
# readers.py
class _DefaultReader:
def read(self, file):
with open(file, mode="r", encoding="utf-8") as file_obj:
for line in file_obj:
print(line)
DEFAULT_READER = _DefaultReader()
The .read() method in this example takes the path to a file, opens it, and prints its content to the screen line by line. This class will play the role of your default reader. The final step is to create a constant, DEFAULT_READER, to store an instance of your default reader. That’s it! You have a class that processes the input files and also a helper class that provides the default reader.
Your users can also code custom readers. For example, they can code readers for CSV and JSON files. Once they’ve written a given reader, they can pass it into the FileHandler class constructor and use the resulting instance to handle files that use the reader’s target file format.
Handling Your Constants in a Real-World Project
Now that you know how to create constants in Python, it’s time to learn how to handle and organize them in a real-world project. You can use several approaches or strategies to this end. For example, you can put your constants in:
- The same file as the code that uses them
- A dedicated module for project-wide constants
- A configuration file
- Some environment variables
In the following sections, you’ll write some practical examples that demonstrate the above strategies for managing constants appropriately.
Putting Constants Together With Related Code
The first and maybe most natural strategy to organize and manage your constants is to define them together with the code that uses them. With this approach, you’ll be defining the constants at the top of the module that contains the related code.
For example, say that you’re creating a custom module to perform calculations, and you need to use math constants like Pi, Euler’s number, and a few others. In this case, you can do something like this:
# calculations.py
"""This module implements custom calculations."""
# Imports go here...
import numpy as np
# Constants go here...
PI = 3.141592653589793
EULER_NUMBER = 2.718281828459045
TAU = 6.283185307179586
# Your custom calculations start here...
def circular_land_area(radius):
return PI * radius**2
def future_value(present_value, interest_rate, years):
return present_value * EULER_NUMBER ** (interest_rate * years)
# ...
In this example, you define your constants in the same module where the code using them lives.
Note: If you want to explicitly communicate that a constant should be used in its containing module only, then you can add a leading underscore (_) to its name. For example, you can do something like _PI = 3.141592653589793. This leading underscore labels the name as non-public, which means that the user’s code shouldn’t use this name directly.
Putting your constants together with the code that uses them is a quick and appropriate strategy for narrow-scope constants that are only relevant to a single module in a given project. In this case, you probably won’t be using the constants outside the containing module itself.
Creating a Dedicated Module for Constants
Another common strategy for organizing and managing your constants is creating a dedicated module in which to put them all. This strategy is appropriate for constants that are used in many modules and even packages across a given project.
The central idea of this strategy is to create an intuitive and unique namespace for constants. To apply this strategy to your calculations example, you can create a Python package containing the following files:
calc/
├── __init__.py
├── calculations.py
└── constants.py
The __init__.py file will turn the calc/ directory into a Python package. Then you can add the following content to your constants.py file:
# constants.py
"""This module defines project-level constants."""
PI = 3.141592653589793
EULER_NUMBER = 2.718281828459045
TAU = 6.283185307179586
Once you’ve added this code to constants.py, then you can import the module whenever you need to use any of your constants:
# calculations.py
"""This module implements custom calculations."""
# Imports go here...
import numpy as np
from