简体   繁体   中英

How to run through a number of functions until one returns False?

I'd like the score function to run the while loop until 1 of the "checks" returns False, and exit the loop if none return False. The "check" also returns a string that defines the message we'll display to user



def check_args(args, number_of_expected_args):
    if len(args) < number_of_expected_args:
        return False, 'cmd_missing_param'
    elif len(args) > number_of_expected_args:
        return False, 'cmd_extra_param'

def check_numbers(args, value):
    if args[value].isdigit() == False:
        return False, 'scores_invalid', 'var3'

def check_score(args, etc):
    if not blahblah....
        return False, 'response3'

def score(ctx, *args):

    test = []
    test[0], test[1] = True, 'Success'
    while test[0] == True:
        test = check_args(args, 4)
        test = check_numbers(args, 2)
        test = check_score(args, 3)
    
    print(test[1])

score(0, 1, 2, 3, 4)

Here is a snip of my working code. This is using discord.py to create a channel command bot, and the checks are to validate the arguments attached to the command.

There are 2 commands defined here, score and schedule , and both call the check_test function, although future commands may only need to run lesser amounts of the checks. So I'm trying to move each individual check outside of my larger check_test function as I'll have many more checks to define and want to be able to call only specific ones

strings = {
    "english": {
        "cmd_missing_param": "Your submission is missing a parameter.",
        "cmd_extra_param": "Your submission has too many parameters.",
        "players_not_found": "Your submission user(s) {var1} cannot be found.",
        "scores_invalid": "Your submitted scores are not valid numbers.",
        "score_submitted": "Score successfully submitted",
        "schedule_submitted": "Schedule successfully submitted"
    }
}
    
async def reply(ctx, dict_string, arg1 = None, arg2 = None):
    # this function is to return a response to the user containing the success/fail message

    author = ctx.author.mention
    dict = strings['english']
    greeting = dict['greeting']
    response = dict[f'{dict_string}']

    return await ctx.reply(f"{greeting} {author}! {response}".format(var1 = arg1, var2 = arg2))

async def check_test(ctx, args, number_of_expected_args, args_players_index, args_scores_index, datetime_index, check_attachment):
    # this function is to perform a number of validations on our command args

    # check if command has expected number of args
    if args != '':
        if len(args) < number_of_expected_args:
            return False, 'cmd_missing_param'
        elif len(args) > number_of_expected_args:
            return False, 'cmd_extra_param'

    # check if the scores are valid numbers
    if args_scores_index != None:
        for each in args_scores_index:
            if args[each].isdigit() == False:
                return False, 'scores_invalid'
        
@client.command()
async def score(ctx, *args):
    # this command is to submit the score record for 2 players

    is_valid, response = await check_test(ctx, args, 4, [0, 1], [2, 3], None, '.w3g')
    if is_valid:
        player1, player2 = args[0], args[1]
        bot_message = await reply(ctx, 'score_submitted', player1, player2)
    else:
        await reply(ctx, response)
    
@client.command()
async def schedule(ctx, *args):
    is_valid, response = await check_test(ctx, args, 4, [0, 1], None, True, None)
    if is_valid: 
        player1, player2 = args[0], args[1]
        bot_message = await reply(ctx, 'schedule_submitted', player1, player2)
    else:
        await reply(ctx, response)

Here's an example of how you might write a validation function for args :

expected_number_of_args = 5


def validate_score_args(args):
    # example: test that exactly 'expected_number_of_args' were passed
    n = len(args)
    if n != expected_number_of_args:
        raise ValueError(f"Expected {expected_number_of_args} args, but got {n}.")

    # example: make sure all args are numeric
    if not all(type(arg) in {int, float} for arg in args):
        raise TypeError(f"Expected all arguments to be numeric.")

    # example: if the above test passed, then check values
    if not all(arg > 0 for arg in args):
        raise ValueError(f"Expected all arguments to be positive.")

    # and so on


def score(ctx, *args):
    try:
        validate_score_args(args)
    except (ValueError, TypeError) as err:
        # Do something about error instead of 're-raising' it, but for now:
        raise err
    
    # If args were valid, then use them:
    return sum(args)

Add any number of "tests" to validate_score_args() . They'll run in order from top to bottom, and if any test fails, none of the following tests will run.

However, I'd recommend always running all your tests, and then "collecting" all the errors and doing something with them (like displaying them to the user) so that the user can see everything they did wrong at once instead of having to play whack-a-mole, fixing one bug at a time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM