Подтвердить что ты не робот

Как вернуть определенную точку после ошибки в цикле "while"

Я пытаюсь написать программу, которая включает цикл 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, программа переходит в начало. Он начинается с начала, а не с y или z. Но в x нет проблем, поэтому программа должна начинать задавать вопросы от y или z, потому что проблема возникла в y или z.

Как я могу запустить программу из определенной точки, например, если есть ошибка только в вопросе y, программа должна начинать задавать вопросы из y или, если только в z, программа должна начинаться с z, а не начало-не x.

Должен ли я использовать более одного цикла while для этого или есть что-то, что заставляет это работать только в одном цикле?

4b9b3361

Ответ 1

[EDIT от генератора к функции]

Вы можете попробовать функцию:

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")

Ответ 2

Я думаю, что это два, очень простых, элегантных решения.

Идея состоит в том, что есть список вопросов, которые нужно задать. Обе реализации продолжают задавать вопросы до тех пор, пока остаются вопросы. Один из них будет использовать метод 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 name" ]

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

ИЗМЕНИТЬ Таким образом, за кулисами все еще есть два цикла (takewhile() - подделка:-)). С небольшим количеством "продуманных решений" это можно сделать без единого цикла:

Рекурсия слова!

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)

Ответ 3

Вы неправильно понимаете, как использовать continue, продолжайте движение к следующей итерации цикла. Чтобы исправить это, просто удалите продолжения

РЕДАКТИРОВАТЬ НА КОММЕНТАРИИ::

Я использую только значения while True, потому что я ничего не знаю о вашей системе

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

Использование break поможет вам достичь желаемого

Ответ 4

Проблема будет решена несколькими циклами. Независимо от того, все ли эти петли находятся на одном месте или выставляются в функции/генераторы/и т.д., Это ваш выбор.

Если бы это был я, я бы загнал вопрос-код в функцию, которая берет сам вопрос, плюс код подтверждения для проверки ответа - функция продолжает задавать вопрос до тех пор, пока проверка не пройдет:

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")

Ответ 5

Да, нет способа вернуться к предыдущей строке в коде после выполнения, кроме как через цикл. Ни в коем случае.

Python и многие современные языки программирования работают таким образом и не поддерживают строку "goto".

Следовательно, именно по этой причине единственный способ сделать это - в какой-то форме множественных циклов, когда цикл повторяется до тех пор, пока не будет получен желаемый результат (либо вложенные петли, либо путем выведения цикла while в функцию as предложенный salparadise).

Ответ 6

Можно ли включить код в функцию? Зная, что вопросы следуют произвольному порядку, вы можете просто использовать блоки 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 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()

В этом коде, набрав "не то, что я хочу", вы вызовете исключение и внутри блока except, ваша функция будет вызвана снова. Имейте в виду, что любой код, который не имеет отступов внутри условия if, будет повторяться столько раз, сколько задавали вопросы, как меры предосторожности.

Ответ 7

Просто перебирайте вопросы с помощью итератора, не вызывайте 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, ("",""))

Ответ 8

Задайте x, y и z до None перед входом в цикл. Затем защитите каждый вопрос с помощью if и снова установите переменную None до continue.

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..  

Ответ 9

Проблема заключается в одной сплоченности программы. Если у вас есть особые вопросы, которые содержат определенные проверки, вы должны написать для них функции.

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 not a number")
          continue
      if response not in range(range_start, range_end+1):
          print(response, 'is not in the range')
      else:
          return response

Ответ 10

Простым решением проблемы будет использование переменной счетчика для решения проблемы. Что-то вроде этого:

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..

Идея состоит в том, чтобы увеличивать счетчик каждый раз, когда что-то идет правильно. После того, как счетчик будет увеличен, он не выполнит другие условия и перейдет прямо в блок кода, где он ошибся.

Ответ 11

Я бы сделал это следующим образом:

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