
Exploring Other Constants in Python
Exploring Other Constants in Python 관련


Apart from user-defined constants, Python also defines several internal names that can be considered as constants. Some of these names are strict constants, meaning that you can’t change them once the interpreter is running. This the case for the __debug__
constant, for example.
In the following sections, you’ll learn about some internal Python names that you can consider and should treat as constants in your code. To kick things off, you’ll review some built-in constants and constant values.
Built-in Constants
According to the Python documentation, “A small number of constants live in the built-in namespace”. The first two constants listed in the docs are True
and False
, which are the Python Boolean values. These two values are also instances of int
. True
has a value of 1
, and False
has a value of 0
:
True
#
# True
False
#
# False
isinstance(True, int)
#
# True
isinstance(False, int)
#
# True
int(True)
#
# 1
int(False)
#
# 0
True = 42
#
# ...
# SyntaxError: cannot assign to True
True is True
#
# True
False is False
#
# True
Note that the True
and False
names are strict constants. In other words, they can’t be reassigned. If you try to reassign them, then you get a SyntaxError
. These two values are also singleton objects in Python, meaning that there’s only one instance of each. That’s why the identity operator (is
) returns True
in the final examples above.
Another important and commonplace constant value is None
, which is the null value in Python. This constant value comes in handy when you want to express the idea of nullability. Just like True
and False
, None
is also a singleton and strict constant object that can’t be reassigned:
None is None
#
# True
None = 42
#
# ...
# SyntaxError: cannot assign to None
None
is quite useful as a default argument value in functions, methods, and class constructors. It’s typically used to communicate that a variable is empty. Internally, Python uses None
as the implicit return value of functions that don’t have an explicit return
statement.
The ellipsis literal (...
) is another constant value in Python. This special value is the same as Ellipsis
and is the only instance of the types.EllipsisType
type:
Ellipsis
#
# Ellipsis
...
#
# Ellipsis
... is Ellipsis
#
# True
You can use Ellipsis
as a placeholder for unwritten code. You can also use it to replace the pass
statement. In type hints, the ...
literal communicates the idea of an unknown-length collection of data with a uniform type:
def do_something():
... # TODO: Implement this function later
class CustomException(Exception): ...
raise CustomException("some error message")
#
# Traceback (most recent call last):
# ...
# CustomException: some error message
# A tuple of integer values
numbers: tuple[int, ...]
The Ellipsis
constant value can come in handy in many situations and help you make your code more readable because of its semantic equivalence to the English ellipsis punctuation sign (…).
Another interesting and potentially useful built-in constant is __debug__
, as you already learned at the beginning of this section. Python’s __debug__
is a Boolean constant that defaults to True
. It’s a strict constant because you can’t change its value once your interpreter is running:
__debug__
#
# True
__debug__ = False
#
# ...
# SyntaxError: cannot assign to __debug__
The __debug__
constant is closely related to the assert
statement. In short, if __debug__
is True
, then all your assert
statements will run. If __debug__
is False
, then your assert
statements will be disabled and won’t run at all. This feature can slightly improve the performance of your production code.
Note
Even though __debug__
also has a dunder name, it’s a strict constant because you can’t change its value once the interpreter is running. In contrast, the internal dunder names in the section below should be treated as constants but aren’t strict constants. You can change their values during your code’s execution. However, this practice can be tricky and would require advanced knowledge.
To change the value of __debug__
to False
, you must run Python in optimized mode by using the -O
or -OO
command-line options, which provide two levels of bytecode optimization. Both levels generate an optimized Python bytecode that doesn’t contain assertions.
Internal Dunder Names
Python also has a broad set of internal dunder names that you can consider as constants. Because there are several of these special names, you’ll just learn about __name__
and __file__
in this tutorial.
Note
To dive deeper into other dunder names in Python and what they mean to the language, check out the official documentation about Python’s data model.
The __name__
attribute is closely related to how you run a given piece of code. When importing a module, Python internally sets __name__
to a string containing the name of the module that you’re importing.
Fire up your code editor and create the following sample module:
print(f"The type of __name__ is: {type(__name__)}")
print(f"The value of __name__ is: {__name__}")
Once you have this file in place, get back to your command-line window and run the following command:
python -c "import sample_name"
#
# The type of __name__ is: <class 'str'>
# The value of __name__ is: sample_name
With the -c
switch, you can execute a small piece of Python code at the command line. In this example, you import the sample_name
module, which prints some messages to the screen. The first message tells you that __name__
is of type str
, or string. The second message shows that __name__
was set to sample_name
, which is the name of the module you just imported.
Alternatively, if you take sample_name.py
and run it as a script, then Python will set __name__
to the "__main__"
string . To confirm this fact, go ahead and run the following command:
python sample_name.py
#
# The type of __name__ is: <class 'str'>
# The value of __name__ is: __main__
Note that now __name__
holds the "__main__"
string. This behavior indicates that you’ve run the file directly as an executable Python program.
The __file__
attribute will contain the path to the file that Python is currently importing or executing. You can use __file__
from inside a given module when you need to get the path to the module itself.
As an example of how __file__
works, go ahead and create the following module:
print(f"The type of __file__ is: {type(__file__)}")
print(f"The value of __file__ is: {__file__}")
If you import the sample_file
module in your Python code, then __file__
will store the path to its containing module on your file system. Check this out by running the following command:
python -c "import sample_file"
#
# The type of __file__ is: <class 'str'>
# The value of __file__ is: /path/to/sample_file.py
Likewise, if you run sample_file.py
as a Python executable program, then you get the same output as before:
python sample_file.py
#
# The type of __file__ is: <class 'str'>
# The value of __file__ is: /path/to/sample_file.py
In short, Python sets __file__
to contain the path to the module from which you’re using or accessing this attribute.
Useful String and Math Constants
You’ll find many useful constants in the standard library. Some of them are tightly connected to some specific modules, functions, and classes. Others are more generic, and you can use them in various scenarios. That’s the case with some math and string-related constants that you can find in the math
and string
modules, respectively.
The math
module provides the following constants:
import math
# Euler's number (e)
math.e
#
# 2.718281828459045
# Pi (π)
math.pi
#
# 3.141592653589793
# Infinite (∞)
math.inf
#
# inf
# Not a number (NaN)
math.nan
#
# nan
# Tau (τ)
math.tau
#
# 6.283185307179586
These constants will come in handy whenever you’re writing math-related code or even code that just uses them to perform specific computations, like your Circle
class back in the Reusing Objects for Maintainability section.
Here’s an updated implementation of Circle
using math.pi
instead of your custom PI
constant:
import math
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius**2
def perimeter(self):
return 2 * math.pi * self.radius
def projected_volume(self):
return 4/3 * math.pi * self.radius**3
def __repr__(self):
return f"{self.__class__.__name__}(radius={self.radius})"
This updated version of Circle
is more readable than your original version because it provides more context on where the Pi constant comes from, making it clear that it’s a math-related constant.
The math.pi
constant also has the advantage that if you’re using an older version of Python, then you’ll get a 32-bit version of Pi. In contrast, if you use Circle
in a modern version of Python, then you’ll get a 64-bit version of Pi. So, your program will self-adapt to its concrete execution environment.
The string
module also defines several useful string constants. The table below shows the name and value of each constant:
Name | Value |
---|---|
ascii_lowercase | abcdefghijklmnopqrstuvwxyz |
ascii_uppercase | ABCDEFGHIJKLMNOPQRSTUVWXYZ |
ascii_letters | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz |
digits | 0123456789 |
hexdigits | 0123456789abcdefABCDEF |
octdigits | 01234567 |
punctuation | !"#$%&'()*+,-./:;<=>?@[\]^_`{ |
whitespace | The combination of the space character, horizontal and vertical tab, linefeed, carriage return, and form feed |
printable | The combination of digits , ascii_letters , punctuation , and whitespace |
These string-related constants come in handy in many situations. You can use them when you’re doing a lot of string processing, working with regular expressions, processing natural language, and more.