在Python for...循环中测试空迭代器

3 投票
4 回答
10665 浏览
提问于 2025-04-15 14:40

下面的代码是基于这个食谱。不过,这个食谱的关键点是,它提供了一种方法,可以在迭代器为空时跳出迭代,但在这里似乎没有效果,反而出现了以下不希望的情况:

  1. 如果get_yes_no_answer() == False,而且迭代器中还有两个或更多的项目,那么next_choice会被跳过,而不是在下次迭代时被选中。
  2. 如果get_yes_no_answer() == False,而且迭代器中剩下的项目少于两个,那么my_func()会返回None。

我该如何确保:

  • 如果get_yes_no_answer() == False,而且迭代器中还有两个或更多的项目,那么next_choice绝对不会被跳过?
  • 如果get_yes_no_answer() == False,而且迭代器中只剩下一个项目,那么my_func()会打印这个项目并调用get_yes_no_answer()
  • 如果get_yes_no_answer() == False,而且迭代器中没有项目了,那么except StopIteration这个部分会被触发?

这是代码:

def my_func(choice_pattern, input):
# Search in input for some things to choose from.
choice_iterator = choice_pattern.finditer(input, re.M)
if not choice_iterator:
    print "No choices. Exiting..."
    sys.exit()
else:
    # Show choices to the user. For each one, ask user for a yes/no response. If
    # choice accepted, return a result. Otherwise show user next choice. If no
    # choices accepted by user, quit.
    for choice in choice_iterator:
        print choice.group()
        # get_yes_no_answer() returns True or False depending on user response.
        if get_yes_no_answer():
            return choice
        else:
            # Check if iterator is empty. If so, quit; if not, do something else.
            try:
                next_choice = choice_iterator.next()
            except StopIteration:
                print "No matches. Exiting..."
                sys.exit()
            else:
                choice_iterator = itertools.chain([next_choice], choice_iterator)

4 个回答

0

可以查看这个问题中的成对迭代器:这个链接。然后你可以像这样检查最后一个项目:

MISSING = object()
for choice, next_choice in pairwise(chain(choice_iterator, [MISSING])):
    print(choice.group())
    if get_yes_no_answer():
        return choice.group()
    if next_choice is MISSING:
        print("No matches. Exiting...")
        sys.exit()

在你展示的例子中,这似乎并不是必要的。你不需要检查finditer是否返回了一个迭代器,因为它总是会返回。而且如果你没有找到想要的内容,你可以直接继续执行for循环:

def my_func(choice_pattern, input):
    """Search in input for some things to choose from."""
    for choice in choice_pattern.finditer(input, re.M):
        print(choice.group())
        if get_yes_no_answer():
            return choice.group()
    else:
        print("No choices. Exiting...")
        sys.exit()
4

你为什么要这样做呢?直接这样不就行了吗:

def get_choice(pattern, inpt):
    choices = pattern.finditer(inpt, re.M)
    if not choices:
        sys.exit('No choices')
    for choice in choices:
        print(choice.group(0))
        if get_yes_no_answer():
            return choice
    sys.exit('No matches')

我不知道你的输入有多长,但我觉得这样做可能不太值得。

2

你不需要检查迭代器是否为空。for循环会自动帮你处理这个问题,当迭代器为空时,它会停止。就是这么简单。

另外,在sys.exit()或者return后面,你也不需要加else

这样一来,你的代码看起来是这样的:

def my_func(choice_pattern, input):
    # Search in input for some things to choose from.
    choice_iterator = choice_pattern.finditer(input, re.M)
    if not choice_iterator:
        print "No choices. Exiting..."
        sys.exit()

    # Show choices to the user. For each one, ask user for a yes/no response. If
    # choice accepted, return a result. Otherwise show user next choice. If no
    # choices accepted by user, quit.
    for choice in choice_iterator:
        print choice
        # get_yes_no_answer() returns True or False depending on user response.
        if get_yes_no_answer():
            return choice
    # Loop exited without matches.
    print "No matches. Exiting..."
    sys.exit()

就这样!

在循环中,你还会获取下一个项目。结果就是你实际上只显示了每第二个答案。

其实,你可以进一步简化代码:

def my_func(choice_pattern, input):
    choice_iterator = choice_pattern.finditer(input, re.M)
    if choice_iterator:
        for choice in choice_iterator:
            print choice
            if get_yes_no_answer():
                return choice
    # If there is no choices or no matches, you end up here:
    print "No matches. Exiting..."
    sys.exit()

迭代器的使用方式和其他序列类型差不多。你不需要把它当成和列表不同的东西来处理。

撰写回答