import random import string # basic version def generatePassword(length, specialChars=False): password = "" # add all basic character types to possible choices choices = string.ascii_lowercase + string.ascii_uppercase + string.digits if specialChars: # add special characters if the argument is specified (e.g. ",-.!%") choices += specialChars for char in range(length): # random.choice() chooses a random character from a list or a string password += random.choice(choices) return password # shorter basic version – if we use empty string ("") as the "specialChars" default value, we don't have to check if the argument is provided! def generatePassword(length, specialChars=""): # if "specialChars" is provided, it will be added to the "choices". If it is not provided, empty string will be added → choices will include only letters and digits choices = string.ascii_lowercase + string.ascii_uppercase + string.digits + specialChars # create a list of random characters generated from "choices" and join them to a string return "".join(random.choice(choices) for i in range(length)) # bonus 1) def generatePassword(length, specialChars="", readable=False): # define a set of characters to be removed from the "choices" similar = "O0l1I" choices = string.ascii_lowercase + string.ascii_uppercase + string.digits + specialChars # check if the generated password should be "readable" → similar characters should be removed from "choices" if readable: # iterate over every character in the "similar" set for char in similar: # ".replace()" function doesn't modify the list (unlike e.g. ".append()"), we have to save the result to the same variable instead choices = choices.replace(char, "") return "".join(random.choice(choices) for i in range(length)) # bonus 2) def generatePassword(length, specialChars=""): # store the possible choices as separate items in a list instead of one string so we can easily pick a category charSets = [string.ascii_lowercase, string.ascii_uppercase, string.digits] # now we have to check if "specialChars" are provided, otherwise the empty string will be appended to "charSets" if specialChars: # we have to append the special characters instead of concatenating them charSets.append(specialChars) # create and empty string to which we will add generated password characters password = "" for i in range(length): # pick a random set of characters first (each set in "charSets" has an equal chance to be picked), e.g. '0123456789' set = random.choice(charSets) # pick a random character from that set char = random.choice(set) # add the character to the password password += char return password # bonus 3) – add arguments to pick which character sets will be used in the password def generatePassword(length, lowercase=True, uppercase=True, digits=True, specialChars=""): choices = "" # check each set if it should be used and add it to the "choices" if lowercase: choices += string.ascii_lowercase if uppercase: choices += string.ascii_uppercase if digits: choices += string.digits if specialChars: choices += specialChars # generate password password = "" for i in range(length): password += random.choice(choices) return password def generatePassword(length, specialChars=""): password = "" choices = string.ascii_lowercase + string.ascii_uppercase + string.digits + specialChars for char in range(length): password += random.choice(choices) # once the password is generated, assume none of the required categories are present in the password lowercase, uppercase, digits, special = False, False, False, False # check which category the character belongs to and mark that category as "fulfilled" (True) for char in password: if char in string.ascii_lowercase: lowercase = True if char in string.ascii_uppercase: uppercase = True if char in string.digits: digits = True if char in specialChars: special = True # if length is too short for the password to contain all required character categories, return None and print a warning message if length < 3 or (length < 4 and specialChars): print "Length is too short." return None if specialChars: # if specialChars are provided (therefore required) and all categories are fulfilled, return the generated password if lowercase and uppercase and digits and special: return password # if not all categories are fulfilled, call this function again with the same arguments (just try again!) else: return generatePassword(length, specialChars) # again, if all categories are fulfilled, return the generated password (special characters are not required this time) elif lowercase and uppercase and digits: return password # again, if not all categories are fulfilled, try again with the same arguments else: return generatePassword(length, specialChars) # bonus - everything in one function. def generatePassword(length, readable=False, specialChars="", lowercase=True, uppercase=True, digits=True): # if the function is called only with "specialChars=True", not with a specified set, provide some baseline special characters if specialChars == True: specialChars = " !#$%&'()*+,-./:;<=>?@[\]^_`{|}~" # define some basic variables choices, similar = [], "Il|1O0" # add each required character set to possible choices if specialChars: choices.append(specialChars) if lowercase: choices.append(string.ascii_lowercase) if uppercase: choices.append(string.ascii_uppercase) if digits: choices.append(string.digits) for similarChar in similar: for charSet in choices: if similarChar in charSet: choices[choices.index(charSet)] = charSet.replace(similarChar, "") # check if the generated password will be long enough to contain all required categories if length < len(choices): print "Desired password length is too short." return None # generate a password password = "".join(random.choice(random.choice(choices)) for i in range(length)) # shorter version of checking if categories are fulfilled for character in password: for charSet in choices: if character in charSet: # if a character belongs to a required category, remove the category from "choices" since the category is already fulfilled choices.remove(charSet) print password, choices # check if the generated password should be readable and starts or ends with a space character (" ") if readable and (password[0] == " " or password[-1] == " "): return generatePassword(length, readable, specialChars, lowercase, uppercase, digits) # if any categories still remain in "choices", they are not present in the password → run this function again if choices: return generatePassword(length, readable, specialChars, lowercase, uppercase, digits) # if no categories remain in "choices", they are all present in the generated password → return the password else: return password print generatePassword(5, True, True)