SoFunction
Updated on 2025-03-01

Use Python 3 to determine the circle complexity of functions

Have you ever seen a "bigma" function that is hundreds of lines long and has intricate logic? Such functions are not only difficult to read, but also difficult to modify, and everyone is afraid to avoid them.

The most important principle of writing functions is: don't write too complicated functions. So what kind of function can be considered too complicated? Generally, two criteria are judged, length and circle complexity.

length

The length is how many lines of code the function has. However, it cannot be said arbitrarily that long functions must be more complicated than short functions. Because under different programming styles, the functions implemented by codes with the same number of lines can be hugely different, and some people can even stuff a complete Tetris game into a line of code.

But even so, length is still of great value for judging the complexity of the function. In the book "Code Collection (2nd Edition), Steve McConnell mentioned that the ideal length range of functions is 65 to 200 lines. Once more than 200 lines, the probability of a bug in the code will increase significantly.

For a highly expressive language like Python, 65 lines are already worthy of attention. If your function exceeds 65 rows, it is highly likely that the function is too complex and has taken on too many responsibilities. Please consider splitting it into multiple small and simple subfunctions (classes).

Circle complexity

"Circle Complexity" is an indicator proposed by Thomas J. McCabe in 1976 to evaluate function complexity. Its value is a positive integer representing the number of linearly independent paths in the program. The greater the value of circle complexity, the more possible execution paths the program will have and the more complex the logic will be.

If the circle complexity of a function exceeds 10, it means it is too complex and the code writer should find a way to simplify it. Optimization writing or splitting into subfunctions are good choices. Next, we will experience the calculation process of circle complexity through actual code.

In Python, the circle complexity of a function can be calculated through the radon tool. Installation command:

pip3 install radon

Suppose we have a code example as follows, the implementation function is a number guessing game, which has 1 whilie and 2 if-else branches judgment logic, file name: complex_func.py.

import random
 
def guess_number():
    # Generate a random number as the answer    answer = (1, 100)
 
    # Initialize the number of guesses    guesses = 0
 
    print("Welcome to the number guessing game! I've figured out a number between 1 and 100, and you need to guess what this number is.")
 
    # Start looping until the player guesses the number    while True:
        # Get the player's guess        guess = int(input("Please enter the number you guessed:"))
 
        # Increase the number of guesses        guesses += 1
 
        # Check the relationship between the numbers guessed by players and the answers        if guess < answer:
            print("The number you guessed is too small, please keep working hard!")
        elif guess > answer:
            print("You guessed the number is too big, please try again!")
        else:
            print(f"congratulations,You guessed it right!The answer is {answer}。You guessed it all {guesses} Second-rate。")
            break  # End the loop 
 
# Call the function to start the gameguess_number()

Next, we use radon to calculate the circle complexity of the corresponding function of this file. The file name is calculated_cyclomatic_complexity.py

from  import cc_visit
 
# Define a Python file pathfile_path = 'complex_func.py'
 
# Use the cc_visit function to calculate the circle complexity of the codewith open(file_path, 'r') as file:
    code = ()
    results = cc_visit(code)
    print(results)
 
# Print the resultsfor result in results:
    print(result)

Execution result: You can see that the function circle complexity is 4.

$ python3 calculate_cyclomatic_complexity.py 
[Function(name='guess_number', lineno=3, col_offset=0, endline=27, is_method=False, classname=None, closures=[], complexity=4)]
F 3:0->27 guess_number - 4

Let's look at another complete code example, where the calculated function is rank(), which is to calculate the rating according to the movie score, and finally outputs the circle complexity and corresponding rating rating level, file name:

get_film_score.py

import radon
from  import cc_rank, cc_visit
 
 
def calculate_complexity(source_code):
    """
    Calculate the cyclomatic complexity of the given source code.
    Parameters:
    source_code (str): The source code to analyze.
    Returns:
    int: The cyclomatic complexity.
    str: The complexity rating.
    """
    try:
        # Visit the AST and calculate the complexity
        results = cc_visit(source_code)
        complexity = results[0].complexity
        # Get the complexity rating
        rating = cc_rank(complexity)
        return complexity, rating
    except Exception as e:
        print("Error:", e)
        return None, None
 
 
# Example usage:
if __name__ == "__main__":
    code = """
def rank(self):
    rating_num = float()
    if rating_num >= 8.5:
        return 'S'
    elif rating_num >= 8:
        return 'A'
    elif rating_num >= 7:
        return 'B'
    elif rating_num >= 6:
        return 'C'
    else:
        return 'D'
    """
    complexity, rating = calculate_complexity(code)
    if complexity is not None and rating is not None:
        print("Cyclomatic Complexity:", complexity)
        print("Complexity Rating:", rating)

Running result: You can see that the function circle complexity is 5 and the rating is A.

Although this value does not reach the dangerous line 10, considering that the function is only 10 short lines, 5 is enough to attract attention.

$ python3 get_film_score.py
Cyclomatic Complexity: 5
Complexity Rating: A

For comparison, let's calculate the rank() function refactored using the bisect module in the case:

def rank(self):
    breakpoints = (6, 7, 8, 8.5)
    grades = ('D', 'C', 'B', 'A', 'S')
    index = (breakpoints, float())
    return grades[index]

Running result: You can see that the function circle complexity is 1 and the rating is A.

$ python3 get_film_score.py
Cyclomatic Complexity: 1
Complexity Rating: A

It can be seen that the circle complexity of the new function has dropped from 5 to 1. 1 is a very ideal value. If the circle complexity of a function is 1, it means that the function has only one main path and no other execution paths. Such functions are usually very simple and easy to maintain.

Of course, in normal project development processes, we generally do not manually execute the radon command after each writing code. Check whether the complexity of the function circle meets the standards, but will configure this check to be automatically executed in the development or deployment process.

This is the article about using Python3 to determine the circle complexity of functions. For more related content on Python3 function circle complexity, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!