简体   繁体   English

有问题的随机密码生成器 (Python 3)

[英]Faulty Random Password Generator (Python 3)

I am beginning to learn Python and started experimenting with an example code block.我开始学习 Python 并开始尝试使用示例代码块。 I edited it a few times, and on the last edit that I did, I added an optional random password generator.我编辑了几次,最后一次编辑时,我添加了一个可选的随机密码生成器。 Then I decided that it would make more sense to put the password generator into a separate document, so I copied the necessary code and made a new document.然后我决定将密码生成器放在一个单独的文档中会更有意义,所以我复制了必要的代码并制作了一个新文档。 After editing it however, I cannot generate an even number of digits in the password.但是,编辑后,我无法在密码中生成偶数位数。

Pastebin糊状

Copy of Faulty Code (Pastebin)错误代码的副本(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')

I refactored your program a bit, and got rid of a lot of unnecessary steps and inconsistencies.我稍微重构了你的程序,去掉了很多不必要的步骤和不一致之处。 Here it is in full, then I'll explain each part:到这里就全了,接下来我来解释一下每个部分:

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 is not just the syntax and builtin functions , it is also the standard library or stdlib. Python 不仅仅是语法和内置函数,它还是标准库或 stdlib。 You're going to be working with the stdlib's modules all the time, so when you think you'll be using one, read the docs!您将一直使用 stdlib 的模块,因此当您认为将使用一个模块时,请阅读文档! You'll learn about the module, what its intended use is, some of its history and changes (such as in which version a certain function was added), and all of the classes, functions, and attributes contained therein.您将了解该模块、它的预期用途、它的一些历史和变化(例如在哪个版本中添加了某个函数),以及其中包含的所有类、函数和属性。 Make sure you read the whole thing (none of them are that long) and try to get at least a basic idea of what each thing does.确保你阅读了整篇文章(没有一篇那么长),并尝试至少对每件事的作用有一个基本的了解。 That way, such as in this case, you'll be able to pick the best function for the job.这样,例如在这种情况下,您将能够为工作选择最佳功能。 One thing I like to do in my spare time is just pick a random module and read the docs, just to learn.我在业余时间喜欢做的一件事就是随机选择一个模块并阅读文档,只是为了学习。 They're generally fairly well written, and usually pretty inclusive.它们通常写得相当好,而且通常非常具有包容性。 Get used to Monty Python references, they're everywhere.习惯 Monty Python 引用,它们无处不在。

import random
import string
import sys

Imports are first, and should almost always be only at the top.进口是第一位的,而且应该几乎总是只排在首位。 I like to put mine in alphabetical order, with the stdlib on top, then a blank line, then 3rd-party modules, including self-written ones next.我喜欢按字母顺序排列我的,stdlib 在上面,然后是一个空行,然后是 3rd-party 模块,接下来包括自己编写的模块。 Put a blank line or two after the imports as well.在导入后也放置一两个空行。 One thing to remember, that I mentioned in the comments: readability counts.要记住的一件事,我在评论中提到的:可读性很重要。 Code is not only meant to be read by machines, but by people as well.代码不仅要由机器阅读,也可以由人阅读。 Comment when necessary.必要时发表评论。 Be generous with whitespace (also remember that whitespace is syntactically important in Python as well, so it forces you to indent properly) to separate related bits of code, functions, classes, blocks, etc. I highly recommend reading, rereading, and spending time pondering PEP-8 , the Python style guide.使用空格(还要记住,空格在 Python 中在语法上也很重要,因此它迫使您正确缩进)以分隔相关的代码、函数、类、块等。我强烈建议您阅读、重读并花时间思考PEP-8 ,Python 风格指南。 Its recommendations aren't absolute , but many projects that enforce coding standards rely on it.它的建议不是绝对的,但许多强制执行编码标准的项目都依赖于它。 Try to follow it as much as you can.尝试尽可能多地遵循它。 If a line comes out to 83 characters, don't sweat it, but be aware of what you're doing.如果一行出现 83 个字符,请不要担心,但要注意您在做什么。

The reason I made such a big deal out of reading the docs is the following few lines:我在阅读文档方面做得如此重要的原因是以下几行:

possible_chars = string.ascii_letters + string.digits + string.punctuation

def nextchar(chars):
    return random.choice(chars)

They get rid of about half of your code.他们删除了大约一半的代码。 string contains a bunch of predefined constants for working with strings. string包含一堆用于处理字符串的预定义常量。 The three I chose should all be good valid password characters.我选择的三个应该都是很好的有效密码字符。 If you're on a system that won't take punctuation marks, just remove it.如果您使用的系统不带标点符号,只需将其删除即可。 Note that possible_chars is a string - like tuples, lists and dicts, strings are iterable, so you don't need to make a separate list of each individual possible character.请注意, possible_chars是一个字符串 - 就像元组、列表和字典一样,字符串是可迭代的,因此您不需要为每个可能的字符制作单独的列表。

Next is the function - it replaces your randInt() , randChar() , and changeCase() functions, along with a bunch of your inline code, which was rather bizarre, to tell you the truth.接下来是函数——它取代了你的randInt()randChar()changeCase()函数,以及一堆你的内联代码,这很奇怪,告诉你真相。 I liked the method you came up with to decide if a letter was upper- or lower-case, but the rest of it was just way too much effort when you have random.choice() and the string constants from above.我喜欢你想出了一个方法来决定,如果一个字母是大写或小写,但它的其余部分只是方式太多精力,当你有random.choice()string从上述参数。

yes_or_no = input("""
Would you like a random password suggestion generated?
Type Yes to continue: """).lower()

You may not have been aware, but you don't need to print() a description string before getting user input() - just pass the string as a single argument to input() and you'll get the same effect.您可能不知道,但在获取用户input()之前不需要print()描述字符串 - 只需将该字符串作为单个参数传递给input() ,您将获得相同的效果。 I also used a triple-quoted """ ( ''' can also be used) string literal that differs from the more common single- ' and double-quoted " string literals in that any newlines or tabs contained within it don't need to be escaped.我还使用了三重引号""" (也可以使用''' )字符串文字,它不同于更常见的单引号'和双引号"字符串文字,其中包含的任何换行符或制表符都不需要被逃脱。 The take-home for now is that you can write several lines of text, and when you print() it, it will come out as several lines.现在最重要的是你可以写几行文本,当你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.")

I used a try/except block for the next part.我在下一部分中使用了try/except块。 If the user enters a non-integer up at the input prompt, the int() function will fail with a ValueError .如果用户在输入提示处输入一个非整数,则int()函数将失败并返回ValueError I picked the simplest manner possible of dealing with it: if there's an error, print a message and quit.我选择了最简单的处理方式:如果出现错误,则打印一条消息并退出。 You can make it so that the program will re-ask for input if an error is raised, but I figured that was beyond the scope of this exercise.您可以这样做,以便程序在出现错误时重新请求输入,但我认为这超出了本练习的范围。

    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.")

Here is where all the action happens.这是所有动作发生的地方。 Using an if/else block, we test the desired length of the password, and if it's between 1 and 25 (an arbitrary upper bound), we generate the password.使用if/else块,我们测试所需的密码长度,如果它在 1 到 25(任意上限)之间,我们生成密码。 This is done with a for loop and the range() function (read the docs for exactly how it works).这是通过for循环和range()函数完成的(请阅读文档以了解其工作原理)。 You'll notice that I use a common Python idiom in the for loop: since I don't actually need the number generated by range() , I "throw it away" by using the underscore _ character in place of a variable.您会注意到我在for循环中使用了一个常见的 Python 习语:因为我实际上不需要range()生成的数字,所以我通过使用下划线_字符代替变量来“扔掉它” Finally, the else statement handles the alternative - either pwd_len is 0 or less, or 26 or greater.最后, else语句处理备选方案 - pwd_len或小于 0,或等于或大于 26。

else:
    print("Well then, why did you run me?")

We're at the end of the program!我们在节目的最后! This else is paired with the if yes_or_no == 'yes': statement - the user entered something other than yes at the input prompt.elseif yes_or_no == 'yes':语句配对 - 用户在输入提示中输入了不是 yes 的内容。

Hopefully this will help you understand a little bit more about how Python works and how to program efficiently using it.希望这能帮助您更多地了解 Python 的工作原理以及如何有效地使用它进行编程。 If you feel like you're spending a bit too much time implementing something that you think should be easier, you're probably right.如果您觉得在实施您认为应该更容易的事情上花费了太多时间,那么您可能是对的。 One of Python's many advantages is its "batteries included" philosophy - there's a huge range of things you can do with the stdlib. Python 的众多优势之一是其“包含电池”的理念——您可以使用 stdlib 做很多事情。

I made some small edits, and my code seems to be working now.我做了一些小的编辑,我的代码现在似乎可以工作了。 Here is the finished product (I put comments to show what the code does, and also to mark the edits.):这是成品(我添加注释以显示代码的作用,并标记编辑。):

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')

Note: I made this code purely to experiment and better learn basic aspects of Python.注意:我编写此代码纯粹是为了试验和更好地学习 Python 的基本方面。 This code is not optimized, and is also not as random as I can (and will) make it.这段代码没有优化,也没有我能(也将)做到的那样随机。

PS Sorry if the comments are incomplete, I am still learning this language. PS对不起,如果评论不完整,我仍在学习这门语言。

I don't know why you are doing over complicated for this simple problem, you can just use the constant provided by the string object, I would rather have the following programs to generate random password我不知道你为什么要为这个简单的问题做得过于复杂,你可以使用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>")

Outputs输出

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-

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM