在 'while' 循环出错后如何 return 特定点

How to return a specific point after an error in 'while' loop

我正在尝试编写一个包含 while 循环的程序,在这个循环中,如果出现问题,我会收到一条错误消息。有点像这样;

while True:

    questionx = input("....")
    if x =="SomethingWrongabout questionX":
        print ("Something went wrong.")
        continue
    other codes...

    questiony = input("....")
    if y == "SomethingWrongabout questionY":
        print ("Something went wrong.")
        continue

    other codes...

    questionz = input("....")
    if z == "SomethingWrongabout questionZ":
       print ("Something went wrong.")
       continue

    other codes..

问题如下:questionX后出现错误,程序重新开始。它从头开始,而不是从 yz 开始。但是在x没有问题,所以,程序应该从yz开始提问,因为,问题发生在yz .

如何让程序从特定点开始,比如如果仅在 y 个问题出现错误,程序必须从 y 开始提问,或者仅在 [=16] =],程序必须从z开始,不是从x.

开始

我应该为此使用一个以上的 while 循环还是有什么东西可以使它只在一个循环中工作?

你误解了continue的使用方式,continue移动到循环的下一次迭代。要解决此问题,只需删除 continues

根据评论进行编辑::

我只使用 while True 值,因为我对您的系统一无所知

while True:
    while True:
        questionx = input("....")
        if x =="SomethingWrongabout questionX":
            print ("Something went wrong.")
            continue
        else:
            break;

利用break将帮助您实现目标

[从生成器编辑到函数]

你可以试试一个功能:

def check_answer(question, answer):
    while True:
        current_answer = input(question)
        if current_answer == answer:
            break
        print "Something wrong with question {}".format(question)
    return current_answer

answerX = check_answer("Question about X?\n", "TrueX")
answerY = check_answer("Question about Y?\n", "TrueY")
answerZ = check_answer("Question about Z?\n", "TrueZ")

不确定您是否要保留这些值,但如果您需要调整它,这应该会给您一些提示。

结果:

Question about X?
"blah"
Something wrong with question Question about X?

Question about X?
"blah"
Something wrong with question Question about X?

Question about X?
"TrueX"
Question about Y?
"TrueY"
Question about Z?
"blah"
Something wrong with question Question about Z?

Question about Z?
"blah"
Something wrong with question Question about Z?

Question about Z?
"TrueZ"

根据评论编辑:

def check_answer(question, answers):
    while True:
        current_answer = input(question)
        if current_answer in answers:
            break
        print "Something wrong with question {}".format(question)
    return current_answer

answerX = check_answer("Question about X?\n", ("TrueX", "TrueY")

是的,执行后无法 return 到代码的前一行,除非通过循环。 根本没办法.

Python 和许多现代编程语言以这种方式工作并且不支持 "goto" 行。

因此,唯一的方法是通过某种形式的多个 while 循环重复执行一条语句,直到收到您想要的结果(嵌套循环,或将 while 循环拉出到一个按照 salparadise 的建议运行。

是否可以将代码放入函数中?知道问题遵循任意顺序,如果答案不符合您的标准,您可以使用 try/except 块,并保留已回答问题的列表。

假设我们有一个全局列表:

answered_questions = []

还有一个帮助函数,让我根据之前列表的长度检查问题是否已经得到解答:

def is_it_answered(index):
    """
    Ckecks whether the question number "index" has already been answered.
    :param index: Number of question inside answered_questions
    :return: True if the question was already asked
    """
    # Checking for the index value to be True may not be necessary, but it's just for safety
    if len(answered_questions) >= index + 1 and answered_questions[index]:
        return True

现在您在主函数中所要做的就是将与每个问题对应的代码放入每个套件中。如果输入了您不想要的答案,请引发异常,而不是在完成该问题背后的逻辑之前做任何您想做的事情。

def ask_questions():

    if not is_it_answered(0):
        try:
            answered_questions.append(True)
            questionx = input("...")

            # Whatever is supposed to make Question X wrong goes here
            if questionx == "not what i want":
                raise Exception

        except Exception:
            print "Something went wrong in question x"
            # do whatever you want to do regarding questionx being wrong
            ask_questions()

        # Rest of Code for Question X if everything goes right

    if not is_it_answered(1):
        try:
            answered_questions.append(True)
            questiony = input("...")

            # Whatever is supposed to make Question Y wrong goes here
            if questiony == "not what i want":
                raise Exception

        except Exception:
            print("Something went wrong")
            # do whatever you want to do regarding questionxy being wrong
            ask_questions()

        # Rest of Code for Question Y if everything goes right

    if not is_it_answered(2):
        try:
            answered_questions.append(True)
            questionz = input("...")

            # Whatever is supposed to make Question Z wrong goes here
            if questionz == "not what i want":
                raise Exception

        except Exception:
            print("Something went wrong")
            ask_questions()

        # Rest of Code for Question Z

        # If this is the last question, you can now call other function or end

if __name__ == "__main__":
    ask_questions()

在此代码中,键入 "not what i want" 将引发异常,并且在 except 块内,将再次调用您的函数。请注意,作为预防措施,任何未在 if 条件内缩进的代码都将按照所提出的问题重复多次。

我认为这里有两个非常简单、优雅的解决方案。

这个想法是有一个要问的问题列表。只要问题仍然存在,这两种实现都会继续询问。只要问题的答案是正确的,一个将使用 itertools.dropwhile() 方法从列表中删除元素,另一个会做一些不同的事情 - 见下文。

在此示例实施中,神奇答案 'foo' 是对任何问题的错误答案。您可以在 Python 中 运行 检查它是否会在您回答 'foo'.

的问题处重新询问(剩余)问题

通过修改ask_question()函数来适应你的情况应该很简单。

import itertools

input = lambda x: raw_input("what is your "+x+"? ")

# returns true or false; wether or not the question was answered 
# correctly
def ask_question(question):
    answer = input(question)
    # could be any test involving answer
    return answer != "foo"

# assume we have a list of questions to ask
questions = [ "age", "height", "dog's name" ]

# keep on looping until there are questions
while questions:
    questions = list(itertools.dropwhile(ask_question, questions))

编辑 所以,在幕后,仍然有两个 while 循环(takewhile() 是一个赠品 :-))。有了一些开箱即用的想法,它甚至可以在没有一个 while 循环的情况下完成:

递归这个词!

def ask_more_questions(question_list):
    # no more questions? then we're done
    if not question_list:
        return
    # ask the first question in the list ...
    if ask_question(question_list[0]):
        # ok, this one was answered fine, continue with the remainder
        ask_more_questions(question_list[1:])
    else:
        # Incorrect answer, try again with the same list of questions
        ask_more_questions(question_list)

如果你愿意,可以压缩成:

def ask(q_list):
    if qlist:
        ask(q_list[1:]) if ask_question(q_list[0]) else ask(q_list)

这个问题将通过多个while循环来解决。这些循环是全部放在一个地方,还是分解到 functions/generators/etc 中,由您选择。

如果是我,我会把提问代码分解成一个函数,该函数接受问题本身,加上验证答案的验证码——该函数会一直提问,直到验证通过:

def ask_question(question, validate):
    while "not valid":
        answer = input(question)
        if validate(answer):
            return answer
        else:
            print(" invalid response, try again")

while True:

    x = ask_question("....", lambda a: a=="SomethingWrongabout questionX")

    ...other codes...

    y = ask_questiony("....", lambda a: a== "SomethingWrongabout questionY")

    ...other codes...

    z = ask_questionz("....", lambda a: a=="SomethingWrongabout questionZ")

只需使用迭代器迭代问题,在获得所需输出之前不要在迭代器上调用 next:

questions = iter(("who is foo", "who is bar", "who is foobar"))
def ask(questions):
    quest = next(questions)
    while quest:
        inp = input(quest)
        if inp != "whatever":
            print("some error")
        else:
            print("all good")
            quest = next(quest, "")

如果您有问题和答案,请将它们压缩在一起:

def ask(questions, answers):
    zipped = zip(questions,answers) # itertools.izip python2
    quest,ans = next(zipped)
    while quest:
        inp = input(quest)
        if inp != ans:
            print("Wrong")
        else:
            print("all good")
            quest, ans = next(zipped, ("",""))

在进入循环之前将xyz设置为None。然后用if保护每个问题,并在continue之前再次将有问题的变量设置为None

x = y = z = None
while True:

    if x is None:
        questionx = input("....")
        if x =="SomethingWrongabout questionX":
            print ("Something went wrong.")
            x = None
            continue

        other codes...

    if y is None:
        questiony = input("....")
        if y == "SomethingWrongabout questionY":
            print ("Something went wrong.")
            y = None
            continue

        other codes...

    if z is None:
        questionz = input("....")
        if z == "SomethingWrongabout questionZ":
           print ("Something went wrong.")
            z = None
           continue

        other codes..  

问题之一是程序的内聚性。如果您有特定的问题需要特定的验证,您应该为它们编写函数..

def getX():
   while True:
      response = input("...")
      if response == "something wrong with x":
         print("Something went wrong with x")
      else:
         return response

def getY():
   ...

然后在你的代码中你只是

x = getX()
y = getY()
z = getZ()

这些函数中的每一个都可以以不同的方式验证输入。如果您的许多验证都属于特定模式,您也可以尝试概括它们。例如

def getInt(name, range_start, range_end):
   prompt = "Enter a number for {} between {} and {}".format(name,
                                                             range_start, 
                                                             range_end)
   while True:
      try:
          response = int(input(prompt))
      raise ValueError:
          print("That's not a number")
          continue
      if response not in range(range_start, range_end+1):
          print(response, 'is not in the range')
      else:
          return response

该问题的一个简单解决方案是使用计数器变量来解决 issue.Something,如下所示:

counter = 0
while True:
    if counter == 0:
        questionx = input("....")
        if x =="SomethingWrongabout questionX":
            print ("Something went wrong.")
            continue
        else:
            counter = counter + 1
         other codes...

    if counter <= 1:
        questiony = input("....")
        if y == "SomethingWrongabout questionY":
            print ("Something went wrong.")
            continue
        else:
            counter = counter + 1
        other codes...

    if counter <= 2:
         questionz = input("....")
         if z == "SomethingWrongabout questionZ":
             print ("Something went wrong.")
             continue
         else:
             counter = counter + 1
        other codes..

我们的想法是在每次正确的时候增加计数器。计数器递增后不会执行其他条件,会直接跳转到出错的代码块

我会这样做:

qa = (
    ('Question X', 'Answer X'),
    ('Question Y', 'Answer Y'),
    ('Question Z', 'Answer Z'),
)

for item in enumerate(qa):
    question = item[1][0]
    answer = item[1][1]
    while True:
        usr = input("What is the answer to %s: " % question)
        if usr == answer:
            break

结果为:

$ python qa.py
What is the answer to Question X: Answer X
What is the answer to Question Y: Answer Y
What is the answer to Question Z: Answer X
What is the answer to Question Z: Answer Z

Process finished with exit code 0