Вложенные функции питоничны?

Я изучаю Python на своем R.Pi, и у меня возникла небольшая загвоздка. Мне кажется, что следующий код оставит функцию «inputchecker» открытой в памяти, пока она возвращается к функции «getinput».

Это плохой код? Стоит ли это делать по-другому?

def getinput(i):    
    if i == 1:
        first = input("Would you like A or B? ")
        inputchecker(1, first)
    elif i == 2:
        second = input("Would you like C or D? ")
        inputchecker(2, second)

def inputchecker(n, userinput):    
    def _tryagain_(n):
        usage(n)
        getinput(n)        
    if n == 1:
        if userinput in ("A", "B"):
            print("You chose wisely.")
            getinput(2)
        else:
            _tryagain_(n)
    elif n == 2:
        if userinput in ("C", "D"):
            print("You chose wisely.")
        else:
            _tryagain_(n)

def usage(u):
    if u == 1:
        print("Usage: Just A or B please.") 
    if u == 2:
        print("Usage: Just C or D please.") 


getinput(1)

person Benjo    schedule 22.11.2016    source источник
comment
Это не совсем питонический язык, поскольку он может вызвать проблемы с непредвиденными истинными операторами if, и это не ограничивается только питоном. Все языки поддерживают этот хак. Лучше использовать цикл while, если только вы не используете цикл while достаточно часто, чтобы поместить его в функцию.   -  person WorkingRobot    schedule 22.11.2016


Ответы (3)


Нет, имя getinput во вложенной функции не создает ссылку. Он просматривается каждый раз, когда вызывается _tryagain_, потому что он глобальный. Не то, чтобы это имело значение, поскольку модуль очищается как единое целое при выходе из Python, здесь нет реальной возможности утечки памяти.

Однако вы используете рекурсию, чтобы запрашивать у пользователей ввод, и вашему коду трудно следовать. Вместо этого используйте простой цикл, см. Спрашивание пользователя для ввода, пока они не дадут правильный ответ.

person Martijn Pieters    schedule 22.11.2016
comment
Отличный отзыв, спасибо. У меня теперь гораздо больше направления, ура. - person Benjo; 22.11.2016

Наличие двух функций, бесконечно вызывающих друг друга, на самом деле не лучший поток управления. Лучше бы с while петлей

def getinput(i):
    while i:    
        if i == 1:
            first = input("Would you like A or B? ")
            i = inputchecker(1, first)
        elif i == 2:
            second = input("Would you like C or D? ")
            i = inputchecker(2, second)

def inputchecker(n, userinput):          
    if n == 1:
        if userinput in ("A", "B"):
            print("You chose wisely.")
            return 2
        else:
            getusage(i)
            return i
    elif n == 2:
        if userinput in ("C", "D"):
            print("You chose wisely.")
        else:
            getusage(i)
            return i

Возможно, было бы даже лучше, если бы вы упростили его до одной функции. Нет причин для разделения.

person Brendan Abel    schedule 22.11.2016

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

Также я бы позволил проверке всегда что-то возвращать - никогда не знаешь: первый аргумент тоже может быть неправильным:

def getinput():
    valid = False
    while not valid:
        first = input("Would you like A or B? ")
        valid = inputIsValid(1, first)
    valid = False
    while not valid:
        second = input("Would you like C or D? ")
        valid = inputIsValid(2, second)
    return [first, second]

def inputIsValid(n, userinput):    
    valid = False
    if n == 1:
        valid = userinput in ("A", "B")
    elif n == 2:
        valid = userinput in ("C", "D")
    if valid:
        print("You chose wisely.")
    else:
        usage(n)
    return valid

def usage(u):
    if u == 1:
        print("Usage: Just A or B please.") 
    elif u == 2:
        print("Usage: Just C or D please.") 

getinput() 
person trincot    schedule 22.11.2016