Pierwszy generator haseł w Pythonie

Sep 10 2020

To mój pierwszy projekt wykorzystujący Python. Zrobiłem prosty generator haseł, który sprawdza dane wejściowe użytkownika. Jak mogę to poprawić?

import random
def password_generator():
    password = []
    letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
               "v", "w", "x", "y", "z"]
    password_length = 0
    password_numbers = []
    password_letters = []
    # Input the length of the password
    while True:
        password_length_input = input("Choose the length of your password with numbers between 6 and 15:\n")
        if not password_length_input.isnumeric():
            print(f"{password_length_input} is not a number, try again:")
            continue
        else:
            password_length = int(password_length_input)
            print(f"Password length: {password_length}")
        if 6 <= password_length <= 15:
            break
        else:
            print("The password must be between 6 and 15 characters, try again:")
            continue
    # Input the amount of numbers in password
    while True:
        password_numbers_input = \
            input(f"Choose the amount of numbers you want in your password, max {password_length}\n")
        if not password_numbers_input.isnumeric():
            print(f"{password_numbers_input} is not a number try again")
            continue
        elif int(password_numbers_input) > password_length:
            password_numbers = 0
            print(f"The value is too high, choose maximum {password_length} numbers")
            continue
        else:
            password_numbers = int(password_numbers_input)
            print(f"Password numbers: {password_numbers}")
            for number in range(0,password_numbers):
                password.append(random.randrange(0,9))
            break
    # Check for numbers and letters in password
    while True:
        if password_numbers == password_length:
            print(f"The password will be only {password_numbers} numbers, no letters.")
            break
        else:
            password_letters = password_length - password_numbers
            print(f"""Your password will be {password_length} characters with {password_numbers} numbers and {password_letters} letters.""")
            for letter in range(0,password_letters):
                password.append(random.choice(letters))
            break
    random.shuffle(password)
    password_string = ''.join([str(item) for item in password])
    print(f"Your password is:\n{password_string}")

password_generator()

Przykład użycia:

Choose the length of your password with numbers between 6 and 15:
Password length: 8
Choose the amount of numbers you want in your password, max 8
Password numbers: 2
Your password will be 8 characters with 2 numbers and 6 letters.
Your password is:
pzc11bmf

Odpowiedzi

9 benrg Sep 10 2020 at 22:06
letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",`
           "v", "w", "x", "y", "z"]

Ta metoda pisania alfabetu jest bardzo podatna na błędy. Importowałbym stringi używałbym string.ascii_lowercasezamiast letters. Jeśli z jakiegoś powodu chcesz wygenerować własny zakres liter, napiszę

letters = [chr(n) for n in range(ord('a'), ord('z') + 1)]

ponieważ wtedy nie ma niebezpieczeństwa pominięcia lub skopiowania listu.


password_length = 0
password_numbers = []
password_letters = []

Te wartości domyślne nigdy nie są używane. Wartości domyślne password_numbersi password_lettersnie mają sensu, ponieważ te zmienne zawierają liczby. Usunąłbym wszystkie trzy linie.


if not password_length_input.isnumeric():
    print(f"{password_length_input} is not a number, try again:")
    continue
else:
    password_length = int(password_length_input)
    print(f"Password length: {password_length}")

Zamiast tego napisałbym

try:
    password_length = int(password_length_input)
except ValueError:
    print(f"{password_length_input} is not a number, try again:")
    continue
print(f"Password length: {password_length}")

while True:
    if password_numbers == password_length:
        ...
        break
    else:
        ...
        break

Nie ma sensu mieć tu whilepętli, ponieważ zawsze wyrywasz się z niej przy pierwszej iteracji.


range(0,password_numbers)

Możesz po prostu pisać range(password_numbers).


password.append(random.randrange(0,9))

Spowoduje to dodanie cyfry od 0 do 8 włącznie, nigdy 9. Jeśli chcesz mieć wszystkie dziesięć cyfr, napisz random.randrange(10). Lub, może lepiej, użyj random.choice(string.digits).


password_string = ''.join([str(item) for item in password])

Jeśli użyjesz, string.digitsto każdy element passwordbędzie znakiem, więc możesz to uprościć do password_string = ''.join(password).

6 Anonymous Sep 10 2020 at 20:31

Prostszy sposób generowania losowego ciągu:

import random
import string

    def get_random_string(length):
        letters = string.ascii_lowercase
        result_str = ''.join(random.choice(letters) for i in range(length))
        print("Random string of length", length, "is:", result_str)
    
    get_random_string(8)
    get_random_string(8)
    get_random_string(6)

zapożyczone stąd , a przykładów jest więcej.

Teraz, jeśli masz określone wymagania, takie jak minimalna liczba cyfr, możesz dostosować formułę lub wygenerować dwie listy i scalić je podczas tasowania wartości.

W linku, który zacytowałem powyżej, jest przykład: „Generuj losowy ciąg alfanumeryczny ze stałą liczbą liter i cyfr” => łączenie dwóch składanych list.

Sposób, w jaki to robisz, jest proceduralny, ale nie Pythonic. To jakby wymyślanie na nowo koła.

Twoja lista dozwolonych znaków powinna wyglądać przynajmniej tak:

letters = "abcdefghijklmnopqrstuvwxyz"

Następnie wybierasz losową literę, np. letters[3]Zwróci „d”, ponieważ lista jest oparta na 0, a Python traktuje ciągi znaków jako ciągi znaków. Używając shuffle, tak jak to już robisz, możesz napisać bardziej zwięzły kod.

3 K.Oleksy Sep 10 2020 at 19:19

Pierwszy

Proponuję stworzyć oddzielne metody dla każdej pętli while.

druga

Myślę, że pętla „while True” nie jest dobrą praktyką. Zamiast tego użyj warunku.

Trzeci

Proponuję stworzyć klasę PasswordGenerator, która będzie zawierała Twój kod. Pomoże Ci to w przyszłości rozszerzyć kod.

Podstawowa struktura projektu

 class PasswordGenerator():
     
    check_declared_password_length():
        ...
        
    check_amount_of_password_numbers():
        ...
    *
    *
    *

Na koniec pamiętajmy o tworzeniu funkcji, na które spoczywa jedna odpowiedzialność. Następnie możesz napisać testy jednostkowe dla każdego z nich i będzie to łatwiejsze.