在Python for...循环中测试空迭代器
下面的代码是基于这个食谱。不过,这个食谱的关键点是,它提供了一种方法,可以在迭代器为空时跳出迭代,但在这里似乎没有效果,反而出现了以下不希望的情况:
- 如果get_yes_no_answer() == False,而且迭代器中还有两个或更多的项目,那么next_choice会被跳过,而不是在下次迭代时被选中。
- 如果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()
迭代器的使用方式和其他序列类型差不多。你不需要把它当成和列表不同的东西来处理。