简体   繁体   中英

Continue for loop without iterating

Is there a keyword that I can use to iterate a for loop without stepping the iterator? I know that it's possible to do this without such a command, by using a while loop and iterating manually, but it would greatly simplify things, in this instance, if I could just use a for loop, since continuing without iteration is the exception, not the rule. (there will significantly more conditions added to this when it is complete, all of which will require iteration). Here's my code (or, what I've written so far):

for line in file_as_list:
    response = input(line)
    if response.lower() == 'help':
        self.show_command_list()
        response = input(line)
    if response.lower() == 'loc':
        self.show_location(file_as_list, location)
        response = input(line)
    if response.lower() == 'exit':
        save_changes = input('Would you like to save the changes you have made? (Y/N) ')
        while (save_changes.upper() != 'Y') & (save_changes.upper() != 'N'):
            save_changes = input('That is not a valid response. Try again. ')
        if save_changes.upper() == 'N':
            temp = file_as_list
            print('Changes were not saved.')
        else:
            for line in file_as_list[location:]:
                temp.append(line)
            print('Changes were saved.')
        break
    if response.lower() == 'inline':
        line += ' //' + input(line + ' //')
        print('Line generated: ' + line)
    location += 1
    temp.append(line)

I think you want two nested loops. Try something like this:

for line in file_as_list:   # outer loop
    while True:             # inner loop
        response = input(line).lower()
        if response == 'help':        # these two options don't exit the inner loop
            ...
        elif response == 'loc':       # so they won't consume a line from the for loop
            ...
        else:
            break

    if response == 'exit':            # these other two conditions are outside the while loop
        ...
    elif response == 'inline':        # so a new line will be fetched after they run
        ...

If either of the first two conditions are met, the inner loop will keep on running without changing line . Only if the break gets hit will the inner loop end, and the other conditions get tested. After they do their thing, a new value will be assigned to line , as the for loop continues iterating.

Unrelated to your main question, I also changed the input line to call lower on the input immediately before saving it to response . That means the conditions don't need to keep calling it repeatedly. Your code isn't wrong there, but if you never care about the user's capitalization, throwing it away right off the bat can simplify things.

You can use an explicit iterator like

it = iter(file_as_list)
for line in it:
    input(line)
   ... 
    input(next(it))

and so on. Just be sure to properly handle the case where you run out of lines!

You have two types of commands: ones that advance the iterator, and ones that don't. You could also call it action vs descriptive commands. Your best bet conceptually is to have a while loop that will continue to seek input until you get an action command. This while loop will live inside the existing for loop.

The advantage of this is that currently, your descriptive commands like "help" and "loc" can't be repeated, but you probably want them to be.

Another decision I would recommend is to use distinct functions to implement each command. By giving the commands a consistent interface, you make the code easier to maintain and understand. By registering the commands in a dictionary, you can make your lookup faster and more flexible.

The following concept has a bunch of functions that return a tri-state boolean value and an update. The boolean is True if the command wants to stay on the current line, False to continue. None to exit. The line update is usually just the input.

# in __init__
...
   self.command_map = {
        'help': self.help,
        'loc': , self.loc,
        'exit': self.exit,
        'inline': self.inline,
    }
    self.temp = []
...

def help(self, file_as_list, location, line):
    self.show_command_list()
    return True, line

def loc(self, file_as_list, location, line):
    self.show_location(file_as_list, location)
    return True, line

def exit(self, file_as_list, location, line):
    save_changes = ''
    while len(save_changes) != 1 or save_changes.upper() not in 'YN':
        save_changes = input('Would you like to save the changes you have made? (Y/N) ')
    if save_changes.upper() == 'N':
        self.temp = file_as_list
        print('Changes were not saved.')
    else:
        self.temp.extend(file_as_list[location:])
        print('Changes were saved.')
    return None, line

def inline(self, file_as_list, location, line):
    line += ' //' + input(line + ' //')
    print('Line generated: ' + line)
    return True, line

def process(self):
    for location, line in enumerate(file_as_list):
        stay = True
        while stay:
            response = input(line)
            command = command_map.get(response.casefold())
            if command is None:
                print(f'Command "{response}" not found. Try again')
            else:
                stay, line = command(file_as_list, location, line)

        if stay is None:
            break
        self.temp.append(line)

Given command_map , you can do lots of things easier: for example, you can reimplement show_command_list to do something with sorted(command_map.keys()) . I'm sure you can see how relatively easy it is to add commands to your list. You don't have to repeat boilerplate code, just be careful with the inputs and return values.

This construction is also much easier to iterate manually if you don't like the idea of having nested loops:

def process(self):
    stay = False
    iterator = enumerate(file_as_list)
    while True:
        if not stay:
            try:
                location, line = next(iterator)
            except StopIteration:
                break
        response = input(line)
        command = command_map.get(response.casefold())
        if command is None:
            print(f'Command "{response}" not found. Try again')
            stay = True
        else:
            stay, line = command(file_as_list, location, line)

        if stay is None:
            break
        if not stay:
            self.temp.append(line)

As you can see, this method requires quite a bit more special handling for the various conditions.

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