Python - Любой способ избежать нескольких if-утверждений внутри друг друга в for-loop?

Мне нужен лучший способ сделать это. Я новичок в программировании, но я знаю, что это очень неэффективный способ сделать это, и что для этого мне нужна функция, я просто не знаю, как это сделать. какие-либо предложения? Я ОЧЕНЬ благодарен за любую помощь!

for H in range(0,len(a_list)):
    if a_list[H] > list4[0]:
        list5 = [number_list[i]]
        if function(list1,list5) == list1[1]:
            if function(list2,list5)== list2[1]:
                if function(list3,list5)== list3[1]:
                    if function(list4,list5)== list4[1]:
                        list5.append(input('some input from the user'))
                        other_function(list5)
                        if list5[1]== 40:
                            print ('something something')
                            break out of EVERY loop 
                         else: 
                            for H in range(0,len(a_list)):
                                if a_list[H] > list5[0]:
                                    list6 = [number_list[i]]
                                    if function(list1,list6) == list1[1]:
                                        if function(list2,list6)== list2[1]:
                                            if function(list3,list6)== list3[1]:
                                               if function(list4,list6)== list4[1]:
                                                  if function(list5,list6)== list5[1]:
                                                     list6.append(input('some input from theuser'))
                                                     other_function(list6)
                                                         if list6[1]== 40:
                                                             print ('something something')
                                                                 break out of EVERY loop 
                                                         else: 
                                                            etc. (one extra comparison every time)  

Ответ 1

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

С учетом этого мы сначала меняем list1, list2, list3,... в список списков (с индексом 0,1,2,3 вместо 1,2,3,4). Кроме того, не называйте это list, потому что это полезное имя для того, что уже полезно. lst довольно популярен в Python. Я также собираюсь изменить list5 в lstA и list6 в lstB, потому что 5 и 6 больше не имеют смысла.

Теперь мы имеем это:

for H in range(0,len(a_list)):
    if a_list[H] > lst[3][0]:
        lstA = [number_list[i]]
        if function(lst[0],lstA) == lst[0][1]:
            if function(lst[1],lstA)== lst[1][1]:
                if function(lst[2],lstA)== lst[2][1]:
                    if function(lst[3],lstA)== lst[3][1]:
                        lstA.append(input('some input from the user'))
                        other_function(lstA)
                        if lstA[1]== 40:
                            print ('something something')
                            break out of EVERY loop 
                         else: 
                            for H in range(0,len(a_list)):
                                if a_list[H] > lstA[0]:
                                    lstB = [number_list[i]]
                                    if function(lst[0],lstB) == lst[0][1]:
                                        if function(lst[1],lstB)== lst[1][1]:
                                            if function(lst[2],lstB)== lst[2][1]:
                                               if function(lst[3],lstB)== lst[3][1]:
                                                  if function(lstA,lstB)== lstA[1]:
                                                     lstB.append(input('some input from theuser'))
                                                     other_function(lstB)
                                                         if lstB[1]== 40:
                                                             print ('something something')
                                                                 break out of EVERY loop 
                                                         else: 
                                                            etc. (one extra comparison every time)  

Теперь более очевидно, что мы в основном делаем то же самое четыре раза.


Если вам нужно сделать то же самое несколько раз, подумайте о циклах.

Мы заменим блоки на циклы. Мы также будем использовать переменную флагов, чтобы отслеживать, не сработало ли что-то при тестировании нашей логики, и используйте логику "если она не работает, пропустите материал", а не "если она работает, делайте что-нибудь"

for H in range(0,len(a_list)):
    if a_list[H] > lst[3][0]:
        continue #reducing indent levels by negating the check:
                 #quit on failure instead of work on success

    lstA = [number_list[i]]

    quit = False

    for j in range(4):
        if function(lst[j],lstA) != lst[j][1]: #testing FALSEHOOD
            quit = True
            break #the j loop only

    if quit:
        continue #reducing indent levels by negating the check

    lstA.append(input('some input from the user'))
    other_function(lstA)
    if lstA[1]== 40:
        print ('something something')
        break #out of EVERY loop
    #else: #don't need the else because we broke

    for H in range(0,len(a_list)):
        if not a_list[H] > lstA[0]:
            continue #reducing indent levels by negating the check

        lstB = [number_list[i]]

        for j in range(4):
            if function(lst[j],lstB) != lst[j][1]: #testing FALSEHOOD
                quit = True;
                break #to the H loop
        if not quit and  function(lstA,lstB)== lstA[1]: #combining two checks
            lstB.append(input('some input from theuser'))
            other_function(lstB)
            if lstB[1]== 40:
                print ('something something')
                break #out of EVERY loop
            else: #at this point I'm lost and can't refactor
                etc. (one extra comparison every time)  

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

Флаг сбоя работает, но не очень изящный. Там преувеличенное высказывание: "... если вам нужно больше трех уровней отступов, вы все равно ввернуты и должны исправить вашу программу" . Прочитайте это как: Если у вас есть много уровней отступов (и некоторые языки требуют больше, чем другие), вы должны подумать о том, можете ли вы переместить часть логики в функцию.

Мы также переместим некоторую повторяющуюся логику в функцию проверки.

(Наконец, я думаю, что это ошибка, когда ваш второй for-loop вложен в ваш первый. Поскольку у них есть одна итераторная переменная H, я думаю, что это вызовет бесконечный цикл. Поэтому я исправил это.)

#returns FALSE if a check fails, unlike the `quit` variable
def checker(lst, lstA):
    for i in range(4):
        if function(lst[i],lstA) != lst[i][1]: #testing FALSEHOOD
            return False;
    return True;


def main(???):
    for H in range(0,len(a_list)):
        if a_list[H] > lst[3][0]:
            continue

        lstA = [number_list[i]]

        if not checker(lst,lstA):
            continue

        lstA.append(input('some input from the user'))
        other_function(lstA)
        if lstA[1]== 40:
            print ('something something')
            return #break out of EVERY loop

    for H in range(0,len(a_list)):
        if not a_list[H] > lstA[0]:
            continue

        lstB = [number_list[i]]

        if checker(lst,lstB) and  function(lstA,lstB) == lstA[1]:
            lstB.append(input('some input from theuser'))
            other_function(lstB)
            if lstB[1]== 40:
                print ('something something')
                return # break out of EVERY loop
            else: #at this point I'm lost and can't refactor
                etc. (one extra comparison every time)  

Ответ 2

Используйте функцию all() для проверки нескольких связанных условий:

if all(function(lst, list5) == lst[1] for lst in (list1, list2, list3, list4)):

и

if all(function(lst, list6) == lst[1] for lst in (list1, list2, list3, list4, list5)):

Как и вложенные операторы if, all() будет короткозамкнуто; return False, как только любой из тестов завершится с ошибкой.

Кроме того, перебирайте списки напрямую, вместо того чтобы генерировать диапазон индексов. Если вы используете break, вам не нужно использовать else, удалив еще один уровень отступов.

Вы можете удалить другой уровень, отфильтровывая a_list:

for H in filter(lambda H: H > list4[0], a_list):

Вместе это уменьшает ваше гнездование до:

for H in filter(lambda H: H > list4[0], a_list):
    list5 = [number_list[i]]
    if all(function(lst, list5) == lst[1] for lst in (list1, list2, list3, list4)):
        list5.append(input('some input from the user'))
        other_function(list5)
        if list5[1]== 40:
            print ('something something')
            break # out of EVERY loop 

        for J in filter(lambda J: J >list5[0], a_list):
            if all(function(lst, list6) == lst[1] for lst in (list1, list2, list3, list4, list5)):
            list6.append(input('some input from theuser'))
            other_function(list6)
            if list6[1]== 40:
                print ('something something')
                break # out of EVERY loop 

            # continue here

Предположительно, ваши фактические исключения использования break (raise CustomException() и try:, except CustomException: # break out of all the loops fast), поскольку регулярный break останавливает текущий цикл.

Если вы постоянно добавляете дополнительные списки и вложенность, вы, вероятно, хотите использовать список для хранения всех этих вложенных списков, а затем просто добавьте во внешний список:

class EndLoops(Exception): pass

stack = [[number_list[0]]]
try:
    for i in number_list[1:]:
        for H in filter(lambda H: H > stack[-1][0], a_list):
            stack.append([i])
            if all(function(lst, stack[-1]) == lst[1] for lst in stack[:-1]):
                stack[-1].append(input('some input from the user'))
                other_function(stack[-1])
                if stack[-1][1] == 40:
                    print ('something something')
                    raise EndLoops
except EndLoops:
    pass # broken out of outer loop

и вдруг все гнездо исчезло; вместо этого вы переместили вложенность в список stack списков.

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