Python 3.10: cyclomatic complexity of match-case syntax

I am wondering about the cyclomatic complexity of using the new match-case syntax in Python 3.10, and later. What is the cyclomatic complexity difference (if any?) of a match-case code as opposed to code that uses the if-elif-else syntax?

So my question is this: Are there any benefits in using the match-case syntax in terms of cyclomatic complexity?

1 Like

Benefits in terms of cyclomatic complexity alone? I doubt it.

Cyclomatic complexity measures only the number of independent paths
through a program, not how complex each path is. So both of these
program snippets have the same cyclomatic complexity:

# Snippet 1
if x == 1:
    print("done")


# Snippet 2
import math
a = x + 4
b = a*20
c = math.sqrt(b)
d = c - 9
flag = int(isinstance(d, list))
e = -2345*flag
f = 3*d + e
if f == 3:
    print("done")

I expect that if you take a match statement, and re-write it in terms of
low-level if…else decision points, there would be the same number of
paths. The difference is that the match cases involve much higher-level
tests and so is a lot less verbose.

Consider:

match sequence:
    case (1, 2, 99, x, 8, y, 0):
        print(x + y)

Which I think we could re-write as:

if instance(sequence, collections.abc.Sequence):
    t1, t2, t3, x, t4, y, t5  = sequence
    if t1 == 1:
        if t2 == 2:
            if t3 == 99:
                if t4 == 8:
                    if t5 == 0:
                        print(x + y)

So the match statement should be counted as the same cyclomatic
complexity as the chain of if statements, but the first version takes
three lines of code and the second eight and five temporary variables.

1 Like

@steven.daprano, now that Python 3.10 final version is out, I have tested the cyclomatic complexity of 2 functions: the 1st incorporates the if-elif-else syntax and the 2nd incorporates the match-case syntax.

1st functon (if-elif-else syntax):

def number_tester(number):
    if number == 1:
        print("Number is 1.")
    elif number == 2:
        print("Number is 2.")
    else:
        print("Number is unknown.")

number_tester(number=1)

2nd function (match-case syntax)

def number_tester(number):
    match number:
        case 1:
            print("Number is 1.")
        case 2:
            print("Number is 2.")
        case _:
            print("Number is unknown.")

number_tester(number=1)

The 1st function has a cyclomatic complexity of 3 as reported by radon:

test.py
    F 1:0 number_tester - A (3)

1 blocks (classes, functions, methods) analyzed.
Average complexity: A (3.0)

And the 2nd function has a cyclomatic complexity of 1 as reported by radon:

test.py
    F 1:0 number_tester - A (1)

1 blocks (classes, functions, methods) analyzed.
Average complexity: A (1.0)

The command used to get the provided results was radon cc "test.py" -a -s.

So, as you can see, the match-case syntax in Python 3.10 does make a difference in terms of cyclomatic complexity of code, i.e., it reduces it.

It looks like radon doesn’t specify compatibility yet with Python 3.10, and it doesn’t look like it recognises match statements yet. That’s why it’s not producing anything.

Are we sure that radon knows how to correctly interpret match
statements? Has it been updated to analyse match statements?

If you were to translate the two Python functions into C, using
if for the first and translating the match statement to a C switch
statement, would you still insist that they have different cyclomatic
complexity?

The documentation for radon doesn’t mention match statements:

https://radon.readthedocs.io/en/latest/intro.html#cyclomatic-complexity

@steven.daprano, thanks for that link. Yes, radon devs apparently haven’t included the match statement yet.

I’m wondering whether they’ll treat match as +0 and then each case statement as +1, or the match statement also as +1?

UPDATE: There is a PR on GitHub that adds the ability for radon to recognize and analyze this new match-case syntax of Python 3.10 and then correctly report the cyclomatic complexity of the code that uses this match-case syntax.

The PR was not merged yet, but I’m sure it will be soon. When it is, we’ll just have to wait for the new version of radon.