Python. Не могу разобраться как повторно вызвать функцию, если она не удовлетворяет условию

Друзья, не могу разобраться как повторно вызывать функцию до момента как она удовлетворит условию. Есть 2 функции - одна генерирует пароль, другая проверяет его на надежность. Как сделать так, чтобы функция генерировала новый пароль, пока он не станет надежным, а попытки генерации до надежного пароля выводила пользователю? Пробовал с циклом while, он у меня берет только один сгенерированный пароль и бесконечно его выводит будь он надежным или нет...

from random import randint
def generate():
    MAX_NUMBER = 10
    MIN_NUMBER = 7
    Generate = chr(randint(33,126))
    Password = []
    Randomno = randint(MIN_NUMBER, MAX_NUMBER)
    for i in range(Randomno):
        Generate = chr(randint(33,126))
        Password.append(Generate)
    W = ''.join(Password)
    return W


def nadezhnost(password):
    has_upper = False
    has_lower = False
    has_numb = False
    for ch in password:
        if ch >= 'A' and ch <= 'Z':
            has_upper = True
        elif ch >= 'a' and ch <= 'z':
            has_lower = True
        elif ch >= '1' and ch <= '9':
            has_numb = True
    if len(password) >= 8 and has_upper and has_lower and has_numb:
        return 'Генерируемый пароль является надежным'
    else:
        return 'Генерируемый пароль является ненадежным'

def main():
    if __name__ == '__main__':
        main()

Ответы (2 шт):

Автор решения: magistar

Как-то так.

from random import randint
def generate():
    MAX_NUMBER = 10
    MIN_NUMBER = 7
    Generate = chr(randint(33,126))
    Password = []
    Randomno = randint(MIN_NUMBER, MAX_NUMBER)
    for i in range(Randomno):
        Generate = chr(randint(33,126))
        Password.append(Generate)
    W = ''.join(Password)
    return W


def nadezhnost(password):
    has_upper = False
    has_lower = False
    has_numb = False
    for ch in password:
        if ch >= 'A' and ch <= 'Z':
            has_upper = True
        elif ch >= 'a' and ch <= 'z':
            has_lower = True
        elif ch >= '1' and ch <= '9':
            has_numb = True
    return len(password) >= 8 and has_upper and has_lower and has_numb
    
    
while True:
    password = generate()
    if nadezhnost(password):
        print('Надёжный пароль:', password)
        break
    else:
        print('Ненадёжный пароль:', password)

В последней строчке проверки на надёжность поменял формат: функция возвращает True или False в зависимости от выполнения вашего условия.

UPD:

Счетчик можно вставить в цикл (перед циклом создаем переменную):

counter = 0
while True:
    password = generate()
    if nadezhnost(password):
        print('Надёжный пароль:', password)
        break
    else:
        print('Ненадёжный пароль:', password)
        counter += 1
print(f'Ненадежный пароль был сгенерирован {counter} раз(а).')
→ Ссылка
Автор решения: Namerek

Вариант который сразу позволяет учесть требования к безопасности пароля и настроить

from random import randint, shuffle, choices
from string import ascii_lowercase, ascii_uppercase, digits, punctuation

def generate(
        # Заданная длина пароля (8 по умолчанию)
        length: int = 8,
        # Минимальное количество цифр в пароле (1 по умолчанию)
        digits_min: int = 1,
        # Минимальное количество букв в нижнем регистре в пароле (1 по умолчанию)
        lower_case_letter_min: int = 1,
        # Минимальное количество букв в верхнем регистре в пароле (1 по умолчанию)
        upper_case_letter_min: int = 1,
        # Минимальное количество специальных символов (знаков пунктуации или других заданных) в пароле (0 по умолчанию)
        special_characters_min: int = 0,
        # Набор специальных символов используемых при создании пароля
        special_characters: str = punctuation
):
    # Создаем шаблон карты символов пароля,
    # то есть сколько каких символов должно быть в пароле
    password_map = [0, 0, 0, 0]


    # заполняем карту рандомными значениями от минимального количества символов до длины пароля до тех пор,
    # пока сумма всех элементов карты не будет равна заявленной длине пароля
    while sum(password_map) != length:
        password_map = [
            # конструкция `and` в данном случае позволяет гарантированно использовать 0
            # если параметр определяющий минимальное количество символов равен нулю и рандомное значение
            # от минимально до длины пароля в противном случае
            digits_min and randint(digits_min, length),
            lower_case_letter_min and randint(lower_case_letter_min, length),
            upper_case_letter_min and randint(upper_case_letter_min, length),
            special_characters_min and randint(special_characters_min, length)
        ]

    # Распаковываем в переменные карту пароля
    digits_len, lower_case_letters_len, upper_case_letters_len, special_characters_len = password_map

    # Собираем пароль по карте (описание choices см. в документации к библиотеке random)
    password_char_list = (
            choices(digits, k=digits_len) +
            choices(ascii_lowercase, k=lower_case_letters_len) +
            choices(ascii_uppercase, k=upper_case_letters_len) +
            choices(special_characters, k=special_characters_len)
    )

    # Перемешиваем список символов
    shuffle(password_char_list)

    # объединяем список в строку и возвращаем в виде результата
    return ''.join(password_char_list)


if __name__ == '__main__':
    print(
        generate(),
        generate(length=20),
        generate(length=15, special_characters='$#@', special_characters_min=2),
        generate(length=10, special_characters_min=1),
        sep='\n'
    )
# C6e8LwF2
# VYVrQLrEZ50hlj2Zq91S
# 2@3415N42$#@h00
# w7Y64YM`73

А задуманную Вами проверку я бы сделал так

def is_safe(
        password,
        /,
        password_min_length: int = 8,
        digits_min: int = 1,
        lower_case_letter_min: int = 1,
        upper_case_letter_min: int = 1
):
    return all(
        [
            len(password) >= password_min_length,
            len([*filter(lambda x: x in digits, password)]) >= digits_min,
            len([*filter(lambda x: x in ascii_lowercase, password)]) >= lower_case_letter_min,
            len([*filter(lambda x: x in ascii_uppercase, password)]) >= upper_case_letter_min
        ]
    )
→ Ссылка