Python — Why don't use Assert like If statement?
Hello, folks! How are you? I hope you are doing very well. Then, in this article, I will talk about some experiences that I had with junior developers trying to change the code a little differently and attempting to "reinvent the wheel" by replacing the "if statement" with an "assert statement". And how it would be a chaos.
But first, I need to explain that I have more than 15 years of experience developing software. Currently, I work primarily with Python, but I have also worked with other programming languages like Java, JavaScript, and PHP.
Let’s move on to the explanation, and I hope this article helps you identify and address some common code issues.
If Statement
The "if" statement solves a lot of problems in software programming. It helps us control our code flow and implement our features. There are many ways to implement it. Some people always use "if/else" and "if/elif/else", while others use only "if" and "elif", treating "else" as the default in the function. And that’s okay; it’s your code, your rules (and your headache! :D).
The fact is that "if" statements and "else" statements are tools that make our code more versatile and enable us to aggregate values to produce results. They can be a game-changer and will determine whether the business succeeds or fails.
P.S.: Failure is associated only with the Product Owner (P.O.) and Chief Officer (C.O.) making wrong decisions, not with coding problems. But success will always be associated with us (the giga master f* developer).
If Statement and some options
In Python, like I mentioned, we can use "if", "elif" and "else", try use only "if" and "elif" keep the default return like "else". So, at this point, I will illustrate the "if", "elif" and "else" implementation.
# Example using if, elif and else
def example_a(x:int):
if x > 10:
return "a"
elif x <= 5:
return "b"
else:
return "c"
# Example using only if and elif
def example_b(x:int):
if x > 10:
return "a"
elif x >= 5:
return "b"
return "c" # the else is like default
We can use the if inline, conditional expressions, you can check more about this in PEP-308:
var_abc = "a" if y >= 10 else "b"
Sometimes, we can employ certain tricks by manipulating the conditional order to create a different expression, effectively suppressing "if" statements. However, this approach can lead to issues in code readability and comprehension, particularly for junior developers or those transitioning from other programming languages. Nevertheless, it does work:
# It only executes the function if first condition was true
y >= 10 and execute_something()
We can also utilize "if" and "else" in different contexts, such as list and dictionary comprehensions (as described in PEP 202 and 274) and even in lambda expressions, for example.
We can employ certain built-in functions like "all" and "any" to modify how we structure "if" and "else" statements when dealing with a list of conditions, as demonstrated below:
conditions = [condition_a, condition_b]
# condition_a and condition_b is True
all(conditions)
# condition_a or condition_b is True
any(conditions)
Python recently introduced the "switch" statement. However, it’s important to exercise caution when using it. I will also clarify which Python version initially incorporated this feature. Here’s an example of its usage:
def example_c(x:int):
match x:
case 10:
return "a"
case 9:
return "b"
case _: # default
return "c"
After this brief explanation about "if-else" and some usage modes, we can now proceed to discuss the use of ‘assert’ statements, similar to "if".
Assert statement
Sometimes, I encounter code that uses the ‘assert’ statement as if it were a conditional statement, even in critical flows that could have a negative impact on the company. It looks something like this:
def xpto(x:int):
assert x >= 5, "Block the flow"
return "Do something"
if __name__ == "__main__":
print(xpto(3))
In this case, when x < 5, it raises an exception with the message "Block the flow" and, by default, returns "Do something". Assuming we have this in a file called "main.py", running it with "python main.py" will produce the expected behavior. It’s fine.
But, if we execute it with debug mode turned off, the result will not be as expected when using "python -O main.py". It will not raise the error and will return "Do something", and this is the problem.
What "-O" do?
remove assert and __debug__-dependent statements; add .opt-1 before .pyc extension; also PYTHONOPTIMIZE=x
In other words, something similar can occur if the machine or Dockerfile has Python debug mode set to "off", for example. Sometimes, these environment variables may not be under your control.
Because of this use the simple way:
def xpto(x:int):
if x < 5:
raise Exception("Block the flow")
return "Do something"
if __name__ == "__main__":
print(xpto(3))
Now, if the debug mode is "off", it will not affect our code and will raise the error as intended. This approach helps reduce external configurations that can impact our code flow.
Another problem with this use of "assert" or running the code in production with debugging "on" is the execution time and increased memory usage.
When we use assert correctly?
Use the "assert" statement to debug our code with simplicity, and we can also use it for testing. It should not be used in a production environment to validate something, as in the example that failed when we used the "python -O" command.
def xpto(x:int):
assert x >= 5, "The x needs to be lowest than 5"
if x < 5:
raise Exception("Block the flow")
return "Do something"
if __name__ == "__main__":
print(xpto(3))
It can be used on your test cases too when you are using PyTest.
def test_answer():
assert my_function(3) == 5
Conclusion
As we saw in this article, only use "assert" for testing and validating certain flows to debug your code. Therefore, we should not use it in production because it can have a negative impact on our production application and may be affected by other teams or environmental configurations.
This way, when we need to raise an exception, use it explicitly and add "if-else" statements instead of the "assert" statement.
I hope this was helpful. Thank you for taking the time to read this. :D