关于异常:在python for…循环中测试空迭代器

Testing for an empty iterator in a Python for… loop

以下代码基于此配方。然而,配方的关键点——如果迭代器为空,它提供了一种在迭代器上中断迭代的方法——似乎在这里不起作用,而是以以下不需要的方式工作:

  • 如果get_yes_no_answer()==false,并且迭代器中还有两个或多个项目,则跳过下一个_选项,而不是在下一个迭代中被选择。
  • 如果get_yes_no_answer()==false,并且迭代器中剩余的项少于两个,则my_func()将返回none。
  • 我如何确保:

    • 如果get_yes_no_answer()==false,并且迭代器中还有两个或多个项,则不会跳过下一个_选项?
    • 如果get_yes_no_answer()==false,并且迭代器中还有一个项目,my_func()将打印它并调用get_yes_no_answer()?
    • 如果get_yes_no_answer()==false且迭代器中没有剩余项,是否触发except stopIteration子句?

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    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)

    你为什么这样做?为什么不只是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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')

    我不知道你输入的长度是多少,但我怀疑这值得麻烦。


    您不需要检查迭代器是否为空。for循环将为您这样做,当迭代器为空时停止。就这么简单。

    另外,在sys.exit()或返回之后,您不需要else

    完成后,您的代码如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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()

    就是这样!

    发生的是你在循环中,也得到下一个项目。结果是你实际上只显示每一秒的答案。

    实际上,您可以更加简化它:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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()

    迭代器几乎和任何序列类型一样被使用。你不需要把它和清单区别对待。


    为什么这么复杂的方法?

    我认为这应该是基本相同的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def my_func(pattern, data):
      choices = pattern.findall(data, re.M)
      while(len(choices)>1):
        choice = choices.pop(0)
        if get_yes_no_answer():
          return choice
        else:
          choices.pop(0)
      else:
        return None


    请参阅这个问题中的成对迭代器。然后您可以检查最后一项,如:

    1
    2
    3
    4
    5
    6
    7
    8
    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循环:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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()