Reputation: 11
I want to generate a random password.
It should be made up of symbol, letter, and digit such as:
tqpV4aJ
I!WZuYvBv7
S@OPToyu0u
a) Contains 6-10 characters
b) Contains exactly 1 symbol from the set {!,@,#,-,@,+,%}.
c) Contains exactly 1 digit, i.e., any of the numbers 0-9 except for the number 5, which is excluded.
d) Contains upper or lower case letters among the remaining characters, except for ’e’ and ’E’, which are excluded
e) The positions of the characters are chosen randomly.
How can I achieve this in a pythonic way?
my attempt (fail: can only output one letter):
import random
import string
symbol=('!','@','#','-','@','+','%')
x= random.choice(symbol)
digit= random.randint(0,9)
if digit!=5:
y= digit
letter= random.choice(string.ascii_letters)
if letter!= 'e' or 'E':
z= letter
def main():
list= x + str(y) + z
size= random.randint(6, 10)
pw=''.join(random.choice(list) for i in range(size))
print pw
main()
Upvotes: 0
Views: 1675
Reputation:
Step 1: upgrade to Python 3, step 2:
import secrets
import string
letter_choices = string.ascii_letters.replace("e", "").replace("E", "")
num_letters = secrets.choice(range(4, 9)) # between 4 and 8 letters
password = [secrets.choice(letter_choices) for _ in range(num_letters)]
symbol = secrets.choice("!@#-+%")
password.insert(secrets.randbelow(len(password) + 1), symbol)
digit = secrets.choice("012346789") # 5 is excluded
password.insert(secrets.randbelow(len(password) + 1), digit)
print(''.join(password))
Upvotes: 0
Reputation: 32878
All the answers written here should use the secrets
module rather than the random
module to generate secret values, including passwords. In particular:
random.randint(0, n)
should be replaced with secrets.randbelow(n+1)
.random.choice(x)
should be replaced with secrets.choice(x)
.random.choices(...)
should be replaced with secrets.SystemRandom().choices(...)
or random.SystemRandom().choices(...)
.random.shuffle(...)
should be replaced with secrets.SystemRandom().shuffle(...)
or random.SystemRandom().shuffle(...)
.The functions in the random
module (including random.randint
, random.choice
, random.choices
, random.sample
, and random.shuffle
) use a global random number generator that's not necessarily designed for information security, so using those functions can make passwords easier to guess than they already are -- especially in view of the maximum length requirement and restricted character distribution you give in your question. In general, whenever random.*
functions are called to generate passwords, they should be replaced by secrets.SystemRandom().*
instead (or a suitable method in the secrets
module).
Upvotes: 2
Reputation: 3328
It sounds like you want:
import random, string
symbols = '!@#-@+%' #choose 1
digits = '123467890' #choose 1
letters = set(string.ascii_letters)-set('eE') #choose 4 to 8
chars = random.sample(letters,random.randint(4,8))
chars.append(random.choice(symbols))
chars.append(random.choice(digits))
random.shuffle(chars)
pwd = ''.join(chars)
Upvotes: 0
Reputation: 340
I believe your approach can be simplified with more listcomps and careful character replacing:
import random
import string
def get_password():
pass_ = [random.choice(list(set(string.ascii_letters) - {"e", "E"})) for i in range(random.randint(6, 10))] # Initial password contains random letters, excluding e and E
index_1 = random.randint(0, len(pass_) - 1)
pass_[index_1] = random.choice(["!", "@", "#", "-", "@", "+", "%"]) # Replace a random character with a symbol
index_2 = index_1 # Initialize index_2 as equal to index_1 so that it will be randomized at least once
while index_1 == index_2: # Ensure the two indexes are not equal
index_2 = random.randint(0, len(pass_) - 1)
pass_[index_2] = str(random.choice([random.randint(0, 4), random.randint(6, 9)])) # Replace the chosen random character with a random digit, excluding 5
return "".join(pass_)
print(get_password())
Upvotes: 0
Reputation: 424
Should be fairly clear from the comments. Basic idea is:
It should be noted this is not secure, and should not be used to actually generate passwords.
import random
import string
# it's nice to have your constants up top and in CAPS
SYMBOLS = ('!', '@', '#', '-', '@', '+', '%')
# it's easy to just omit '5' from a list of numbers
# easier to just have the list already be strings than mess around with ints
NUMBERS = ('0', '1', '2', '3', '4', '6', '7', '8', '9')
# quick list comprehension to omit 'e' and 'E'
LETTERS = [char for char in string.ascii_letters if char != 'e' and char != 'E']
# put all our logic in a function
def create_password_insecure():
# pick a symbol
chosen_symbol = random.choice(SYMBOLS)
# pick a number
chosen_number = random.choice(NUMBERS)
# pick some letters to fill out our 6-10 chars
# we pick 4-8 not 6-10, since 2 chars will be symbol/number
number_of_letters = random.randint(4, 8)
# quick list comprehension to pick our letters
chosen_letters = [random.choice(LETTERS) for i in range(number_of_letters)]
# get all our elements in a single list
password_elements_list = [chosen_symbol] + [chosen_number] + chosen_letters
# (pseudo)randomize the list
random.shuffle(password_elements_list)
pseudorandom_password = ''.join(password_elements_list)
print (pseudorandom_password)
create_password_insecure()
Upvotes: 0