Один студент дал мне следующий код:

def addtwo():
 numb=input("enter any number")
 add=int(numb)+2
 print(add)
 inp = input("do you wish to enter again")
 while inp=="yes":
       addtwo()

После первой итерации, если пользователь вводит что-нибудь кроме «да», тело цикла while не выполняется, как ожидалось. Но если мы введем «да», он выполнится (опять же, как и ожидалось) и предложит «ввести любое число», но во второй итерации, даже если пользователь вводит что-нибудь, кроме «да» в «хотите ли вы ввести еще раз» , тело цикла while все еще выполняется. Теперь я запустил на нем отладчик и обнаружил, что значение inp просто меняется на 'yes' при выполнении строки 5. Перед выполнением строки значение inp, согласно отладчик остается тем, что ввел пользователь. Почему это так?

Теперь я поискал это здесь, но не смог найти никакого объяснения, хотя я нашел способ обойти это, добавив возврат перед вызовом addtwo() в теле цикла while (я нашел его здесь: рекурсивный вызов функции для пользовательского ввода), но не мог понять, почему значение inp просто изменяется в локальном стеке, и как оператор return исправляет это?

Вот рабочий код:

def addtwo():
     numb=input("enter any number")
     add=int(numb)+2
     print(add)
     inp = input("do you wish to enter again")
     while inp=="yes":
           return addtwo()

И, чтобы добавить к моей загадке, код просто отлично работает, если мы используем оператор if вместо while.

2
Umair Rafique 2 Янв 2018 в 19:31

2 ответа

Лучший ответ

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

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

Несмотря на эти различия, если вы изо всех сил пытаетесь понять рекурсивный вызов, копирование и вставка - хороший способ подумать об этом. Попробуем это для вашей функции. Следующий код эквивалентен тому, что вы написали, если вы не набираете «да» слишком много раз:

def addtwo0():
     numb=input("enter any number")
     add=int(numb)+2
     print(add)
     inp = input("do you wish to enter again")
     while inp=="yes":
           return addtwo1()

def addtwo1():
     numb=input("enter any number")
     add=int(numb)+2
     print(add)
     inp = input("do you wish to enter again")
     while inp=="yes":
           return addtwo2()

def addtwo2():
     numb=input("enter any number")
     add=int(numb)+2
     print(add)
     inp = input("do you wish to enter again")
     while inp=="yes":
           raise Exception("tried to recurse too deeply!")

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

def addtwo():
     numb0=input("enter any number")
     add0=int(numb0)+2
     print(add0)
     inp0 = input("do you wish to enter again")
     while inp0=="yes":
         numb1=input("enter any number")
         add1=int(numb1)+2
         print(add1)
         inp1 = input("do you wish to enter again")
         while inp1=="yes":
             numb2=input("enter any number")
             add2=int(numb2)+2
             print(add2)
             inp2 = input("do you wish to enter again")
             while inp2=="yes":
                 raise Exception("tried to recurse too deeply!")

Теперь вы можете увидеть непосредственную причину проблемы: установка для inp2 значения "да" не устанавливает для inp1 или imp0 значение "да". Или в исходном коде установка для inp значения «да» во вложенном вызове addtwo не устанавливает для внешнего imp значение «да», потому что каждая функция имеет свой собственный набор переменных.

Теперь вы также можете увидеть основную причину проблемы: для этого не нужно несколько циклов. Для повторной проверки условия достаточно либо рекурсии (с if), либо цикла while. Имея и то, и другое, даже если вы решите непосредственную проблему, вы усложняете задачу излишне. В этом случае цикл while действительно будет самым простым; поместите в него оператор input и полностью избавьтесь от рекурсивного вызова.

1
Arthur Tacca 2 Янв 2018 в 17:35

Резюме

Это связано с тем, что после того, как вы один раз ввели «да», эта функция будет повторяться вечно, независимо от того, что делает следующий рекурсивный вызов.

Вы можете исправить свой код, изменив:

while inp == "yes":
    add_two()

К

if inp == "yes":
    add_two()

Пройдите

  • add_two называется
  • пользователь вводит число
  • их спрашивают, хотят ли они продолжить
  • они вводят "да"
  • в то время как imp == "yes" теперь всегда будет истинным
  • он вызывает add_two
    • они вводят число
    • они вводят "нет"
    • цикл не запускается, поэтому возвращается к первому вызову add_two
  • обратно в цикл while. он по-прежнему оценивается как истина, поэтому продолжает вызывать add_two

Заявление о возврате

По умолчанию в python функции, которые ничего не возвращают, фактически возвращают None. Это означает, что вы вызываете add_two, и если пользователь не вводит «да» в ответ на запрос, он вернется, что затем заставит первый вызов также вернуться.

3
dangee1705 2 Янв 2018 в 16:46