Неисправный генератор случайных паролей (Python 3)
Я начинаю изучать Python и начал экспериментировать с примером блока кода. Я редактировал его несколько раз, и при последнем редактировании я добавил дополнительный генератор случайных паролей. Тогда я решил, что было бы разумнее поместить генератор паролей в отдельный документ, поэтому я скопировал необходимый код и создал новый документ. Однако после его редактирования я не могу сгенерировать четное количество цифр в пароле.
Копия ошибочного кода (Pastebin)
import math
import random
alpha = ['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']
print('Would you like a random password suggestion generator', 'Yes or No')
permissionRandomGenerator = input().lower()
print('How long do you want your password?')
lengthRandomGenerator = int(input())
if permissionRandomGenerator == 'yes':
def randInt():
return math.floor(random.random()*10)
def randChar():
return alpha[math.floor(random.random()*27)]
randPasswordList = []
listInsert = 0
def changeCase(f):
g = round(random.random())
if g == 0:
return f.lower()
elif g == 1:
return f.upper()
while listInsert < lengthRandomGenerator:
randPasswordList.insert(listInsert, randInt())
listInsert = listInsert + 1
if listInsert >= lengthRandomGenerator:
break
randPasswordList.insert(listInsert, randChar())
randPasswordList[listInsert] = changeCase(randPasswordList[listInsert])
listInsert = listInsert + 1
continue
listInsert = 0
printList = 0
if lengthRandomGenerator <= 0:
print('It has to be longer than that')
elif lengthRandomGenerator >= 25:
print('I can\'t generate a password that long')
elif math.isnan(lengthRandomGenerator):
print('error: not valid data type')
else:
while printList < (len(randPasswordList)-1):
printItem = randPasswordList[printList]
print(printItem)
printList = printList + 1
printList = 0
randPasswordList = []
elif permissionRandomGenerator == 'no':
print('Too bad...')
else:
print('You had to answer Yes or No')
3 ответа
Я немного переработал вашу программу и избавился от множества ненужных шагов и несоответствий. Вот это в полном объеме, тогда я объясню каждую часть:
import random
import string
import sys
possible_chars = string.ascii_letters + string.digits + string.punctuation
def nextchar(chars):
return random.choice(chars)
yes_or_no = input("""
Would you like a random password suggestion generated?
Type Yes to continue: """).lower()
if yes_or_no == 'yes':
try:
pwd_len = int(input('How long do you want your password? '))
except ValueError:
sys.exit("You need to enter an integer. Please start the program over.")
if 0 < pwd_len < 26:
new_pwd = ""
for _ in range(pwd_len):
new_pwd += nextchar(possible_chars)
print("Your new password is:\n" + new_pwd)
else:
print("I can only generate passwords between 1 and 25 characters long.")
else:
print("Well then, why did you run me?")
Python - это не только синтаксис и встроенные функции, это также стандартная библиотека или stdlib. Вы будете работать с модулями stdlib все время, поэтому, когда вы думаете, что будете использовать один из них, прочитайте документы! Вы узнаете о модуле, его предполагаемом использовании, его истории и изменениях (например, в какой версии была добавлена определенная функция), а также обо всех классах, функциях и атрибутах, содержащихся в нем. Убедитесь, что вы все прочитали (ни один из них не такой длинный) и постарались получить хотя бы базовое представление о том, что делает каждая вещь. Таким образом, как в этом случае, вы сможете выбрать лучшую функцию для работы. Одна вещь, которую я люблю делать в свободное время, это просто выбрать случайный модуль и читать документы, просто чтобы узнать. Они, как правило, довольно хорошо написаны, и, как правило, довольно инклюзивно. Привыкайте к ссылкам Monty Python, они везде.
import random
import string
import sys
Импорт - первый, и почти всегда должен быть только наверху. Мне нравится помещать мои в алфавитном порядке, с stdlib вверху, затем пустой строкой, затем сторонними модулями, включая написанные самостоятельно. Поставьте пустую строку или две после импорта. Следует помнить одну вещь, о которой я упоминал в комментариях: читаемость имеет значение. Код предназначен для чтения не только машинами, но и людьми. Комментарий при необходимости. Будьте щедрыми с пробелами (также помните, что пробелы также синтаксически важны в Python, поэтому он заставляет вас делать отступы правильно) для разделения связанных фрагментов кода, функций, классов, блоков и т. Д. Я настоятельно рекомендую читать, перечитывать и тратить время обдумывая PEP-8, руководство по стилю Python. Его рекомендации не являются абсолютными, но многие проекты, которые применяют стандарты кодирования, полагаются на него. Постарайтесь следовать этому как можно больше. Если строка содержит 83 символа, не переживайте, но помните о том, что вы делаете.
Причина, по которой я так много прочитал в документах, заключается в следующих нескольких строках:
possible_chars = string.ascii_letters + string.digits + string.punctuation
def nextchar(chars):
return random.choice(chars)
Они избавляются от примерно половины вашего кода. string
содержит набор предопределенных констант для работы со строками. Все три, которые я выбрал, должны быть хорошими действительными символами пароля. Если вы работаете в системе, которая не использует знаки препинания, просто удалите ее. Обратите внимание, что possible_chars
является строкой, подобной кортежам, спискам и диктам, строки являются итеративными, поэтому вам не нужно составлять отдельный список для каждого отдельного возможного символа.
Следующая функция - она заменяет вашу randInt()
, randChar()
, а также changeCase()
функции, наряду с кучей вашего встроенного кода, который был довольно странным, чтобы сказать вам правду. Мне понравился метод, который вы придумали, чтобы решить, является ли буква заглавной или строчной, но остальное было слишком много усилий, когда у вас есть random.choice()
и string
константы сверху.
yes_or_no = input("""
Would you like a random password suggestion generated?
Type Yes to continue: """).lower()
Возможно, вы не знали, но вам не нужно print()
строка описания перед получением пользователя input()
- просто передайте строку как один аргумент input()
и вы получите тот же эффект. Я также использовал тройные кавычки """
('''
также может использоваться) строковый литерал, который отличается от более распространенного '
и в двойных кавычках "
строковые литералы, в которых любые символы новой строки или табуляции, содержащиеся в нем, не должны быть экранированы. Главная задача на данный момент - вы можете написать несколько строк текста, и когда вы print()
это, он выйдет в несколько строк.
try:
pwd_len = int(input('How long do you want your password? '))
except ValueError:
sys.exit("You need to enter an integer. Please start the program over.")
Я использовал try/except
блок для следующей части. Если пользователь вводит нецелое число в строке ввода, int()
функция потерпит неудачу с ValueError
, Я выбрал самый простой способ справиться с ним: если есть ошибка, распечатайте сообщение и выйдите. Вы можете сделать так, чтобы программа повторно запросила ввод, если возникнет ошибка, но я решил, что это выходит за рамки этого упражнения.
if 0 < pwd_len < 26:
new_pwd = ""
for _ in range(pwd_len):
new_pwd += nextchar(possible_chars)
print("Your new password is:\n" + new_pwd)
else:
print("I can only generate passwords between 1 and 25 characters long.")
Здесь происходит все действие. Используя if/else
Блок, мы проверяем желаемую длину пароля, и если она составляет от 1 до 25 (произвольная верхняя граница), мы генерируем пароль. Это сделано с for
петля и range()
функция (прочитайте документы, чтобы узнать, как именно это работает). Вы заметите, что я использую общую идиому Python в for
цикл: так как на самом деле мне не нужно число, сгенерированное range()
Я выбрасываю это с помощью подчеркивания _
символ вместо переменной. Наконец, else
оператор обрабатывает альтернативу - либо pwd_len
0 или меньше, или 26 или больше.
else:
print("Well then, why did you run me?")
Мы в конце программы! это else
в паре с if yes_or_no == 'yes':
утверждение - пользователь ввел что-то отличное от да в строке ввода.
Надеюсь, это поможет вам понять немного больше о том, как работает Python и как эффективно программировать, используя его. Если вы чувствуете, что тратите слишком много времени на реализацию того, что, по вашему мнению, должно быть проще, вы, вероятно, правы. Одним из многих преимуществ Python является его философия "батарейки включены" - с помощью stdlib вы можете выполнять множество задач.
Я сделал несколько небольших правок, и теперь мой код работает. Вот готовый продукт (я помещаю комментарии, чтобы показать, что делает код, а также чтобы пометить изменения.):
import math
import random #Import necessary modules
alpha = ['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'] #List with alphabet
print('Would you like a random password suggestion generator', 'Yes or No') #Prints the question for permission
permissionRandomGenerator = input().lower() #Stores the answer of the above question in lower case
if permissionRandomGenerator == 'yes': #Generates a password if the answer of the first question is 'yes'
print('How long do you want your password?') #Asks for length
lengthRandomGenerator = int(input()) #Stores length as an integer
def randInt(): #Creates a random integer
return math.floor(random.random()*10)
def randChar(): #Selects a random string from the list with the alphabet
return alpha[math.floor(random.random()*27) - 1]
randPasswordList = [] #Creates a list to store the password
listInsert = 0 #Creates a list index variable
def changeCase(f): #Defines a function to randomly change the case of letters before adding them to the list randPasswordList
g = round(random.random())
if g == 0:
return f.lower()
elif g == 1:
return f.upper()
while listInsert < lengthRandomGenerator + 1: #Creates a random password and inserts it into randPasswordList (I added `+ 1` here)
randPasswordList.insert(listInsert, randInt())
listInsert = listInsert + 1
if listInsert >= lengthRandomGenerator:
break
randPasswordList.insert(listInsert, randChar())
randPasswordList[listInsert] = changeCase(randPasswordList[listInsert]) #Calls the changeCase function whenever it inserts a letter
listInsert = listInsert + 1
continue
listInsert = 0
printList = 0
if lengthRandomGenerator <= 0: #If the length it 0 or less (for example, negatives) the password will not generate (I need to fix this a little bit. Currently the code attempts to create a password beforehand)
print('It has to be longer than that')
elif lengthRandomGenerator >= 25:
print('I can\'t generate a password that long')
elif math.isnan(lengthRandomGenerator): #Currently this doesn't do anything, it needs to be moved farther forward
print('error: not valid data type')
else:
while printList < (len(randPasswordList)-1): #Prints the list item by item
printItem = randPasswordList[printList]
print(printItem)
printList = printList + 1
printList = 0 #Resets the variables
randPasswordList = []
elif permissionRandomGenerator == 'no':
print('Too bad...')
else:
print('You had to answer Yes or No')
Примечание: я сделал этот код исключительно для того, чтобы экспериментировать и лучше изучать основные аспекты Python. Этот код не оптимизирован, а также не так случайно, как я могу (и буду) делать.
PS Извините, если комментарии неполные, я все еще изучаю этот язык.
Я не знаю, почему вы делаете слишком сложным для этой простой проблемы, вы можете просто использовать константу, предоставленную string
объект, я бы предпочел следующие программы для генерации случайного пароля
import random, sys, string
def pgen(length=8):
if length < 8:
length = 8
keys = list(string.printable[:-6])
random.shuffle(keys)
return ''.join(keys)[:length]
if __name__ == '__main__':
try:
print( pgen(int(sys.argv[1])))
except Exception as e:
print("Provide length of password \n passwordgen.py <length_of_password>")
Выходы
magautam@nix1947:/tmp$ python passwordgen.py 12
HNLxi!{.qe=b
magautam@nix1947:/tmp$ python passwordgen.py 45
}w5u?+C=e[DfI.n'*1G(m{r0FH|UBKz/@kL>;Sh`tEW8-