Disabling Assertions in Production
To learn more about managed attributes, look no further than Managing Attributes With Python’s property().
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.
00:50
Firstly, run Python with the -O
or -OO
options, and secondly, set the PYTHONOPTIMIZE
environment variable to an appropriate value.
01:00
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.
01:15
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 True
.
01:29 It’s a constant because you can’t change its value once the Python interpreter is running.
01:41
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.
02:01
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.
02:22
If __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.
03:04
You can disable all your assert
statements by having the __debug__
constant set to False
. To accomplish this task, you can use Python’s -O
or -OO
command-line options to run the interpreter in optimized mode.
03:18
The -O
option internally sets __debug__
to False
. This change removes the assert
statements and any code that you’ve explicitly introduced under a conditional targeting __debug__
.
03:30
The -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.
04:24
Because the -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.
04:45
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.
04:55
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.
05:27
Now .radius
is a managed attribute that provides setter and getter methods using the @property
decorator.
05:36
You’ve moved the validation code from .__init__()
to the setter method, which is called whenever the class changes the value of .radius
.
06:10
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.
06:56
You can see that this updated version of Circle
validates the value of .radius
before assignment, and the class works correctly.
07:03
It raises a ValueError
for negative values of .radius
. You’ve fixed the bug with an elegant solution.
07:14
An interesting side effect of running Python in optimized mode is that code under an explicit if __debug__
condition is also disabled.
07:26
Consider the script on-screen. The script explicitly checks the value of __debug__
in an if
… else
statement. The code in the if
block will only run if __debug__
is true.
07:41
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.
08:16
Now you know the basics of using Python’s -O
and -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.