Skip to content

Python Constants: Demystifying Immutable Values

CodeMDD.io

Python Constants: Improve Your Code’s Maintainability

Understanding Constants and Variables

Variables and constants are two fundamental concepts in computer programming. In Python, variables are used to store values that may change during a program’s execution. On the other hand, constants are names representing values that remain unchanged throughout the program.

What Variables Are

Variables in Python are used to store and manipulate data. They can hold different types of values, such as numbers, strings, or objects. Variables can be assigned values and can be updated or reassigned to a different value during the program’s execution.

message = "Hello, World!"
print(message) # Output: Hello, World!
message = "Welcome to Python!"
print(message) # Output: Welcome to Python!

In the example above, the variable message is assigned to the string “Hello, World!” initially and then reassigned to “Welcome to Python!” later.

What Constants Are

Constants in Python are also used to store values, but unlike variables, their values remain fixed throughout the program. Constants are names that represent values that are not meant to be changed.

In Python, there is no dedicated syntax for defining constants. Instead, constants are typically defined using uppercase letters to indicate that their values should not be modified.

PI = 3.14159
MAX_SIZE = 100

In the example above, PI and MAX_SIZE are constants that hold the value of PI and the maximum size, respectively. The convention of using uppercase letters makes it clear to other developers that these values shouldn’t be modified.

Why Use Constants

Constants provide several benefits in Python programming, including:

  1. Readability: Constants with meaningful names make the code more readable and self-explanatory.

  2. Maintainability: Using constants reduces the chances of accidentally modifying important values, making it easier to maintain and debug code.

  3. Reusability: Constants can be reused throughout the codebase, ensuring consistency and avoiding redundant values.

When to Use Constants

Constants should be used whenever a value is meant to stay the same throughout the program’s execution. Some examples of situations where constants are useful include:

  • Mathematical or scientific formulas that require fixed values like PI or the speed of light.
  • Configuration settings or parameters that need to be consistent across different parts of the codebase.
  • API keys or credentials that should remain secure and unchanged.

By using constants, you can enhance the clarity, reliability, and maintainability of your Python code.

Defining Your Own Constants in Python

In Python, you can define your own constants by assigning values to variables using uppercase letters. Although these variables can technically be reassigned, the naming convention makes it clear that they should remain unchanged.

User-Defined Constants

To define user-defined constants in Python, simply follow the convention of using uppercase letters and assign the desired value to the variable.

MY_CONSTANT = 42

In the example above, MY_CONSTANT is a user-defined constant holding the value 42.

Module-Level Dunder Constants

Another way to define constants in Python is by using module-level dunder (double underscore) variables. These constants are defined at the top level of a Python module and are typically written in uppercase to indicate their constant nature.

constants.py
MY_CONSTANT = 42
ANOTHER_CONSTANT = "Hello, World!"

In the example above, the module constants.py defines two constants: MY_CONSTANT and ANOTHER_CONSTANT. These constants can be accessed from other modules using the import statement.

main.py
import constants
print(constants.MY_CONSTANT) # Output: 42

Putting Constants Into Action

Once you have defined constants in Python, you can leverage them to improve the readability, reusability, and maintainability of your code.

Replacing Magic Numbers for Readability

Magic numbers are hard-coded values found in code without any explanation of their purpose. They can make the code difficult to understand and modify. By replacing magic numbers with named constants, you make the code more readable and self-explanatory.

# Without constants
if num == 5:
print("Number is equal to 5")
# With constants
TARGET_NUMBER = 5
if num == TARGET_NUMBER:
print("Number is equal to 5")

In the example above, the constant TARGET_NUMBER replaces the magic number 5, making the code more readable and easier to understand.

Reusing Objects for Maintainability

Constants can also be used to store and reuse objects throughout the codebase. This can improve the maintainability of the code by centralizing the creation and configuration of these objects.

# Without constants
database = Database("localhost", "mydb")
api = API("https:https://codemdd.io/myapi.com")
# With constants
DATABASE_CONFIG = ("localhost", "mydb")
API_BASE_URL = "https:https://codemdd.io/myapi.com"
database = Database(*DATABASE_CONFIG)
api = API(API_BASE_URL)

In the example above, the constant DATABASE_CONFIG stores the configuration for the database, and API_BASE_URL stores the base URL for an API. By using constants, you can easily update or modify these values in a single place.

Providing Default Argument Values

Constants can also be used to provide default values for function arguments. This can be especially useful when defining functions that require some default behavior.

# Without constants
def multiply_numbers(a, b=1):
return a * b
# With constants
DEFAULT_MULTIPLIER = 1
def multiply_numbers(a, b=DEFAULT_MULTIPLIER):
return a * b

In the example above, the constant DEFAULT_MULTIPLIER provides a default value for the b argument in the multiply_numbers function. This ensures consistent behavior when the function is called without explicitly specifying a value for b.

Handling Your Constants in a Real-World Project

In real-world projects, it’s important to organize and manage constants effectively. Here are some approaches to handling constants in Python projects.

One way to organize constants is by placing them in the same module or file as the code that uses them. This keeps the constants close to the code they relate to and makes them easier to find and manage.

database.py
DATABASE_HOST = "localhost"
DATABASE_NAME = "mydb"
class Database:
...
# api.py
API_BASE_URL = "https:https://codemdd.io/myapi.com"
class API:
...

In the example above, the constants DATABASE_HOST, DATABASE_NAME, and API_BASE_URL are defined in the same files as the classes Database and API, respectively. This makes it clear which constants are used by each piece of code.

Creating a Dedicated Module for Constants

For larger projects, it may be beneficial to create a dedicated module just for constants. This module can contain all the constants used throughout the project, making it easier to manage and update them.

constants.py
DATABASE_HOST = "localhost"
DATABASE_NAME = "mydb"
API_BASE_URL = "https:https://codemdd.io/myapi.com"

In the example above, the constants DATABASE_HOST, DATABASE_NAME, and API_BASE_URL are defined in a dedicated module called constants.py. Other modules can import this module to access the constants.

database.py
import constants
class Database:
def __init__(self):
self.host = constants.DATABASE_HOST
self.name = constants.DATABASE_NAME

Storing Constants in Configuration Files

Another approach to managing constants is by storing them in external configuration files. This allows the constants to be easily modified without modifying the code itself.

config.ini
[database]
host = localhost
name = mydb
[api]
base_url = https:https://codemdd.io/myapi.com

In the example above, the constants for the database and API are stored in an INI configuration file. The values can be loaded and used in the code using appropriate libraries or parsing techniques.

Handling Constants as Environment Variables

Environment variables are another way to handle constants that may vary depending on the environment or deployment. By using environment variables, you can easily configure constants without modifying the code.

import os
DATABASE_HOST = os.getenv("DATABASE_HOST", default="localhost")
DATABASE_NAME = os.getenv("DATABASE_NAME", default="mydb")

In the example above, the constants DATABASE_HOST and DATABASE_NAME are loaded from environment variables. If the environment variables are not present, default values are used instead.

Exploring Other Constants in Python

Python provides several built-in constants that are useful in different scenarios.

Built-in Constants

Python’s built-in constants include:

  • True and False: Represent the boolean values True and False.
  • None: Represents the absence of a value or a null value.
  • NotImplemented: Represents a method or operation that is not implemented.
  • Ellipsis: Represents a placeholder or omitted code.

Internal Dunder Names

Python also provides internal dunder (double underscore) names that can be used to override certain behaviors or access specific attributes.

  • __name__: The name of the current module.
  • __file__: The path of the current file.
  • __class__: The class to which an instance belongs.

Useful String and Math Constants

Python’s math and string modules provide useful constants for working with numbers and strings, such as:

  • math.pi: The mathematical constant pi.
  • math.e: The mathematical constant e.
  • string.ascii_letters: A string containing all ASCII letters.
  • string.digits: A string containing all decimal digits.

Type-Annotating Constants

Type annotations can be used to specify the type of a constant in Python. This provides additional clarity and can help catch type-related errors during development.

PI: float = 3.14159
MAX_SIZE: int = 100

In the example above, the constants PI and MAX_SIZE are annotated with their respective types. This makes it clear what types of values these constants should hold.

Defining Strict Constants in Python

To make constants strictly constant in Python and prevent accidental modifications, you can use various techniques.

The .__slots__ Attribute

By defining the .__slots__ attribute in a class, you limit the attributes that can be added to instances of that class. This can be used to enforce constants in instances of a specific class.

The @property Decorator

The @property decorator can be used to define read-only properties in Python classes. By using this decorator, you can prevent direct modification of the property’s value.

The namedtuple() Factory Function

The namedtuple() factory function can be used to create classes with named fields or members. The fields in a named tuple are immutable and cannot be modified once set.

The @dataclass Decorator

The @dataclass decorator, introduced in Python 3.7, can be used to define immutable data classes. Data classes have fields that cannot be modified after creation, enforcing constant-like behavior.

The .__setattr__() Special Method

By defining the .__setattr__() special method in a class, you can control the behavior when an attribute is assigned a new value. This can be used to prevent modifications to specific attributes and enforce constant-like behavior.

Conclusion

Constants play a crucial role in Python programming, providing a way to represent and use unchanging values throughout a program’s execution. By understanding how to define and use constants, you can significantly improve your code’s readability, maintainability, and reusability.

Throughout this tutorial, you’ve learned how to properly define constants in Python, identify built-in constants, use constants to improve code quality, organize and manage constants in real-world projects, explore other Python constants, and enforce strict constant behavior.

By applying the concepts and techniques covered in this tutorial, you’ll be able to write cleaner, more robust Python code that is easier to read and maintain.