DEV Community

Victor Silva
Victor Silva

Posted on

2 2

Python Ternary My case against the "ternary operator" in Python

Ternary what?

Ternary operators, also known as conditional expressions in Python, can be used to make our code shorter:

import random
n = random.randint(1, 100)
# This (classic if-else)...
if n % 2:
msg = 'Odd'
else:
msg = 'Even'
# ... is the same as this (ternary / conditional expression):
msg = 'Odd' if n % 2 else 'Even'
view raw devto0004-01.py hosted with ❤ by GitHub

But i don't like them for two reasons:

1. They often go against the Zen of Python

If you don't know the Zen of Python, start a Python interpreter and type import this. The Zen is a set of guiding principles for writing Python code.

Arguably, most of the time conditional expressions are likely to break 3 of these principles:

  • Beautiful is better than ugly.
    • E.g.: 'Odd' if n % 2 else 'Even' is anything but beautiful
  • Sparse is better than dense.
    • E.g.: 'Odd' if n % 2 else 'Even' is more dense than an if/else statement
  • Readability counts.
    • E.g.: 'Odd' if n % 2 else 'Even' is not as readable as an if/else statement

And, more importantly...

2. They often trick our test coverage

Conditional expressions may make us think that we've covered all possible branches with tests when we actually have not. Check the following example:

def semester(month: int) -> int:
return 1 if month <= 6 else 2
def test_scenario_01():
assert semester(month=3) == 1
view raw devto0004-02.py hosted with ❤ by GitHub

If I run the tests with coverage, this is the output:

According to the image, I covered 100% of the lines, without missing any branch. But looking again at the code, we can see that there is no test for months of the second semester of the year.

If I use the classic if statement instead, the lack of coverage will be correctly detected:

def semester(month: int) -> int:
if month <= 6:
return 1
return 2
def test_scenario_01():
assert semester(month=3) == 1
view raw devto0004-03.py hosted with ❤ by GitHub

If I run the coverage exporting the results to HTML, I can actually see which statement was skipped and which branch was partially run during the test:

Now I know that I should write a test that calls semester with a value greater than 6 if I want the function to be 100% covered.

Conclusion

These are the reasons why I avoid conditional expressions and advise people to avoid them too: they tend to break the Zen of Python and they can fool our code coverage tools.

Granted, not every piece of code does need to be 100% covered by tests, but the ones that do should be measurable in the best way possible, and we've just seen that conditional expressions can get in our way when we are pursuing that.

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (2)

Collapse
 
billturner profile image
Bill Turner

That's interesting about the code coverage problem with the Python ternary. I'm just starting to learn Python myself, and I'll admit their ternary was disappointing to learn. It's the same as the CoffeeScript ternary, which I'm also not a fan of.

Neat and informative post!

Collapse
 
victorosilva profile image
Victor Silva

Thanks!

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay