To learn more about managed attributes, look no further than Managing Attributes With Python’s property().
Disabling Assertions in Production
00:00 Disabling Assertions in Production for Performance. Let’s say you’ve come to the end of your development cycle. Your code has been extensively reviewed and tested. All of your assertions pass, and the code is ready for a new release. At this point, you can optimize the code for production by disabling the assertions that you added during development, but why should you optimize your code in this way?
00:26 Assertions are great during development, but in production, they can affect the code’s performance. For example, a codebase with many assertions running all the time can be slower than the same code without assertions.
00:38 Assertions take time to run, and they consume memory, so it’s advisable to disable them in production, but how can you actually disable them? Well, you have two options.
Firstly, run Python with the
-OO options, and secondly, set the
PYTHONOPTIMIZE environment variable to an appropriate value.
In this section, you’ll learn how to disable your assertions by using these two techniques. Before doing this, you’ll get to know the built-in
__debug__ constant, which is the internal mechanism which Python uses to disable assertions.
Python has a built-in constant called
__debug__. This constant is closely related to the
assert statement. Python’s
__debug__ is a Boolean constant, which defaults to
01:29 It’s a constant because you can’t change its value once the Python interpreter is running.
Here, you first confirm that
__debug__ is a Python built-in that’s always available for you.
True is the default value of
__debug__, and there’s no way to change its value once the interpreter is running.
The value of
__debug__ depends on which mode Python is running in, normal or optimized. Normal mode is typically used during development, while optimized mode is what you should use in production. Now, what does
__debug__ have to do with assertions? In Python, the
assert statement is the equivalent to the code seen on-screen.
__debug__ is true, then the code under the outer
if statement runs. The inner
if statement tracks
expression for truthiness and raises an
AssertionError only if the expression is not true. On the other hand, if
__debug__ is false, then the code under the outer
if statement doesn’t run, meaning that your assertions will be disabled. In this case, Python is running in optimized mode.
02:47 Normal or debug mode allows you to have assertions in place as you develop and test the code. Once your current development cycle is complete, then you can switch to optimized mode and disable the assertions to get your code ready for production.
You can disable all your
assert statements by having the
__debug__ constant set to
False. To accomplish this task, you can use Python’s
-OO command-line options to run the interpreter in optimized mode.
-O option internally sets
False. This change removes the
assert statements and any code that you’ve explicitly introduced under a conditional targeting
-OO option does the same as
-O and also discards docstrings. To see this in action, open your command line or terminal within the directory containing the
circle.py file, and run an interactive session with a
python -O command or
bpython -O, as seen on-screen.
03:52 Once in the interpreter, run the following code.
-O option disables assertions, the
Circle class now accepts a negative radius. As already seen, this behavior is wrong because you can’t have a circle with a negative radius.
04:37 Additionally, the circle’s area is computed using the wrong radius as an input.
The potential to disable assertions in optimized mode is the main reason why you mustn’t use
assert statements to validate input data but as an aid to debugging and testing.
Note that assertions are typically turned off in production code to avoid any overhead or side effects they may cause. A Pythonic solution for the
Circle class would be to turn the
.radius attribute into a managed attribute using the
@property decorator. This way, you perform the
.radius validation every time the attribute changes.
.radius is a managed attribute that provides setter and getter methods using the
You’ve moved the validation code from
.__init__() to the setter method, which is called whenever the class changes the value of
For more about managed attributes, check out this Real Python course. Now, the updated
Circle class works as expected, even if you run the code in optimized mode.
You can see that this updated version of
Circle validates the value of
.radius before assignment, and the class works correctly.
It raises a
ValueError for negative values of
.radius. You’ve fixed the bug with an elegant solution.
An interesting side effect of running Python in optimized mode is that code under an explicit
if __debug__ condition is also disabled.
Consider the script on-screen. The script explicitly checks the value of
__debug__ in an
else statement. The code in the
if block will only run if
__debug__ is true.
If it’s false, then the code in the
else block will run. Now, try running the script in normal and optimized mode to check its behavior. When you execute the script in normal mode, the code under the
if __debug__ condition runs because
__debug__ is true. On the other hand, when you execute the script in optimized mode,
__debug__ changes to false, and the code under the
else block runs.
Now you know the basics of using Python’s
-OO options to disable your assertions in production code. However, running Python with either of these options every time you need to run your production code seems repetitive and may be error-prone. To automate the process, you can use the
PYTHONOPTIMIZE environment variable, and that’s what you’ll be looking at in the next section of the course.
Become a Member to join the conversation.