Как заставить функцию python запускаться заново, если условия не выполнены?

#python #arrays #function #loops

#python #массивы #функция #циклы

Вопрос:

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

 def spread_rumor(array):
    
    new_array = np.zeros_like(array)                                #make a copy of your city

    for i in range(array.shape[0]):                                 #for each index i for the number of rows:
        for j in range(array.shape[1]):                             #for each index j for the number of columns
            if array[i,j] == 0:
                new_array[i,j] = 0
            elif array[i,j] == 2:
                new_array[i,j] = 2
            elif array[i,j] == 1:                                   #if the value of the city/board at [i,j] is a 1:
                new_array[i,j] = 1                                  #we only do something if we find a person who can learn the rumor
                neighbors = getNeighborValues(i,j, array)           #get all of the values of their neighborhood cells
                if np.any(np.array(neighbors) == 2) == True:
                    new_array[i,j] = 2                       
                                                                    
            ## there is more than one way to do this!
            ## You could use a loop to check all the neighbors and move one once you find one
            ## or you could check to see if there is a 2 in any of the neighbors


            

    frac_empty = np.count_nonzero(array == 0)/array.size

    frac_house = np.count_nonzero(array == 1)/array.size
    
    frac_rumor = np.count_nonzero(array == 2)/array.size
    

    if frac_empty   frac_rumor == 1.0:                                           #the copy of our city is the same as city: 
        ##our simulation isn't changing anymore,
        ##so making a copy and updating it isn't going to
        ##lead to further changes
        spread_rumor = False   
    else:
        ##there are still changes going on
        #this is where I would want it to start back over at the top again

    return showCity(new_array)                 #this function creates a plt.imshow representation of the resulting array

  

Ответ №1:

Есть несколько циклов, которые вы могли бы применить для достижения чего-то подобного. Во-первых, while цикл. while циклы, как вы, возможно, знаете, выполняются до тех пор, пока не будет выполнено условие. Если у вас много условий, while оператор может стать довольно уродливым. Многие предпочитают использовать while True , если условий много. Использование break завершит цикл.

 def rand_string():
    while True:
        string = "".join(random.sample("abcdefghijk", 7))
        if string == "afedgcb":
            break
        elif string == "cdefgab":
            break
        elif string == "gbadcef":
            break
        else:
            continue

    return string
  

Выше мы выбираем 7 случайных букв из строки abcdefghijk и проверяем, составляют ли 7 случайных букв либо afedgcb , cdefgab , либо gbadcef . Если это так, мы выходим из цикла и возвращаем строку. Если нет, мы перезапустим цикл. В else/continue этом нет необходимости, цикл все равно начнется заново, если ни одно из условий не будет выполнено, потому что мы не выходим из цикла.

Другой вариант — рекурсия. В приведенном ниже примере просто выбирается случайное число из 0 и 10 и проверяется, равно ли оно 5. Если это так, мы возвращаем число. Если нет, мы просто запускаем функцию снова.

 def rand_num_recursion():
    num = random.randint(0,10)
    if num == 5:
        return num
    else:
        return rec()
  

Теперь, если бы вы это сделали print(rec()) , ответ всегда был бы 5. Почему? Потому что функция будет продолжать выполняться до тех пор, пока случайно выбранное число не будет равно 5. Эта рекурсивная функция также может быть легко преобразована в while цикл:

 def rand_num_while():
    num = random.randint(0,10)
    while num != 5:
        num = random.randint(0,10)
    return num
  

Что, если у вас есть параметры?

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

 def empty_list(lst):
    if len(lst) == 0:
        return lst
    else:
        print(lst)
        return empty_list(lst[:-1]) # return all members of the list except for the last one
  

Когда вы пишете print(empty_list([1,2,3,4,5,6])) и сохраняете print(lst) в функции, результат выглядит следующим образом:

 [1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5]
[1, 2, 3, 4]
[1, 2, 3]
[1, 2]
[1]
[]
  

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