【问题标题】:High complexity preventing function from高复杂度防止功能
【发布时间】:2021-04-04 01:13:50
【问题描述】:

首先,因为我使用的代码很大,所以here 是代码的链接。

如果给出特定输入,我有这个函数可以运行其他函数:

allowed_commands = ['help', 'joblist', 'job', 'jobresign', 'work', 'bal', 'balance', 'dep', 'deposit', 'with', 'withdraw', 'fish', 'hunt', 'shop', 'buy', 'sell', 'hunt', 'fish', 'multiply']

def gamePlay():
    while True:
        command = input(f"{bright_green}Command (type [help] to see list of all commands):\n>> ")
        while command in allowed_commands:
            # <-- Display Rules -->
            if command == 'help':
                rules()
                break

            # <-- Display Jobs -->
            elif command == 'joblist':
                joblist_function()
                break

            # <-- Get Jobs -->
            elif command == 'job' and working == False:
                job_funtion()
                break

            elif command == 'job' and working == True:
                print(f"\n{red}You are already doing a job. You can't work on two jobs,that is dumb...\n")
                break

            # <-- Resign Job -->
            elif command == 'jobresign':
                job_resign()
                break

            # <-- Work -->
            elif command == 'work' and working == True:
                work()
                break
            
            elif command == "work" and working == False:
                print(f"{red}\nLOL, you don't have a job, how you gonna work?\n")
                break

            # <-- Deposit -->
            elif command == 'dep' or command == 'deposit' and deposit_allowed != deposited:
                dep_money()
                break

            elif command == 'dep' or command == 'deposit' and deposit_allowed == deposited:
                print("You have a full bank kiddo...")
                break

            # <-- Balance -->
            elif command == 'bal' or command == 'balance':
                display_balance()
                break

            # <-- Withdraw -->
            elif command == 'with' or command == 'withdraw' and deposited != 0:
                withdraw_money()
                break
            
            elif command == 'with' or command == 'withdraw' and deposited == 0:
                print(f"{red}\nNo money deposited. What are you even trying to wothdraw LOL?\n")
                break

            elif command == 'shop':
                shop()
                break

            elif command == 'beg':
                beg()
                break
def beg():
    global money
    random_number2 = random.choice([0, 1, 2])
    random_money = random.choice(range(100, 500))

    if random_number2 == 1:
        print("Ewwww beggar. No stonks for u")
    
    if random_number2 == 2:
        print(f"Mr.beggar, you can have ⏣ {random_money}.")
        money += random_money

但函数下方绿线上的工具提示显示“圈复杂度太高:17(阈值 15)”。

通常,即使复杂度高达 30,这也适用于我的代码。但最后一个 elif 之后的代码不起作用。即使我输入'beg',该函数也不会运行:

Command (type [help] to see list of all commands):
>> beg
Command (type [help] to see list of all commands):
>> beg
Command (type [help] to see list of all commands):
>> 

为什么会发生这种情况,我该如何解决?

【问题讨论】:

  • 请重读How to create a Minimal, Reproducible Example。我们至少需要allowed_commandsbeg() 来提供帮助。考虑将这个大的if-else 块转换为使用dict,以便决定执行哪个函数。它对您的圈复杂度警告没有帮助,但它是 Python 中的标准做法,在许多其他语言中将是 switch 块。
  • 在这种情况下我将如何使用 dict。我将在没有函数和列表的情况下重新编辑它
  • 这个错误我不熟悉,但我认为用“if”替换“elif”可以解决问题。无论如何,你打破了循环,所以替换不会改变你的代码行为。
  • @GenisBillionaire,我认为您不明白:IDE 中的工具提示警告与代码的执行方式无关。这里也不例外,还有其他事情正在发生,我们需要查看其余引用的代码以提供帮助。 dict 不会解决这个问题。
  • 好的,我会添加需要的东西

标签: python function if-statement cyclomatic-complexity


【解决方案1】:

根据sonarQube docs,

循环复杂度根据通过代码的路径数计算。每当一个函数的控制流分裂时,复杂度计数器就会加一。每个函数的最小复杂度为 1。此计算因语言而略有不同,因为关键字和功能确实如此。

虽然这个圈复杂度可能因语言而异,但通常情况下,循环和条件一起形成 30 的圈复杂度。通过总结以下关键字,我们可以估计圈复杂度为 30(请注意,实际算法可能不同)。

    while 
        while  
            if ... 
            elif ... 
            elif ... and ... 
            elif ... and ...  
            elif ... 
            elif ... and ... 
            elif ... and ... 
            elif ... or  ... and ... 
            elif ... or  ... and ... 
            elif ... or  ... 
            elif ... or  ... and ... 
            elif ... or  ... and ... 
            elif ... 
            elif ... 

虽然较高的圈复杂度在代码中不是一个好习惯,但这只是一个警告,您的代码将照常编译。

在您的情况下,不执行您的beg 命令的问题是,beg 不存在于您的allowed_commands 中。

【讨论】:

    【解决方案2】:

    你可以像这样使用字典:

    {
        'help': rules,
        'joblist': joblist_function,
    }[command]()
    

    但你也可以像这样进行一些重构:

    from typing import Callable, Dict
    
    
    class Game:
        def __init__(self) -> None:
            self.deposit_allowed = 1000
            self.deposited = 0
    
        def play(self) -> None:
            commands = self._get_commands()
    
            while True:
                command = input(f"{bright_green}Command (type [help] to see list of all commands):\n>> ")
    
                if command not in commands:
                    print('Wrong command!')
                    continue
    
                commands[command]()
    
        def _get_commands(self) -> Dict[str, Callable[[], None]]:
            return {
                'help': self._rules,
                'joblist': self._joblist_function,
                'deposit': self._deposit_money,
                'dep': self._dep_money,
                # ...
            }
    
        def _rules(self) -> None:
            pass
    
        def _joblist_function(self) -> None:
            pass
    
        def _deposit_money(self) -> None:
            if self.deposit_allowed == self.deposited:
                print("You have a full bank kiddo...")
                return
    
            self._dep_money()
    
        def _dep_money(self) -> None:
            pass
    
    
    Game().play()
    

    【讨论】:

      猜你喜欢
      • 2020-06-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-28
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      相关资源
      最近更新 更多