Complementando:
Em Python, existe uma construção que não é comum em outras linguagens mainstream: um loop for ou while pode ter um else associado. A ideia é que este bloco só é chamado caso o loop não seja interrompido por break. Exemplo:
itens = # lista contendo vários elementos
for i in itens:
if criterio(i): # se o elemento satisfaz algum critério qualquer
print(f'Encontrado: {i}')
break
else:
print('Nenhum elemento encontrado')
Ou seja, se algum elemento satisfaz o critério, entra no if, imprime a mensagem que foi encontrado e o break interrompe o loop. Neste caso, como o loop foi interrompido com break, o bloco else não é executado.
Mas caso nenhum elemento satisfaça o critério, o loop não será interrompido por break, e depois que o for terminar, o bloco else é executado (ou seja, imprime "Nenhum elemento encontrado").
Esta é uma construção interessante, e não sei dizer porque não é adotado por mais linguagens. Pois caso não existisse, o normal seria fazer algo do tipo:
# se não existisse o for-else
itens = # lista contendo vários elementos
encontrado = None
for i in itens:
if criterio(i): # se o elemento satisfaz algum critério qualquer
encontrado = i
break
if encontrado is not None:
print(f'Encontrado: {encontrado}')
else:
print('Nenhum elemento encontrado')
Ou seja, usar alguma variável para determinar se o elemento foi ou não encontrado, e testá-la depois para saber o resultado. Porém, eu acho que neste caso o for-else fica mais limpo e direto.