So I need to generate a 10-digit password (needs to use the random module) that must contain 2 lower ase letters, 2 uppercase letters, 3 special symbols and 3 numbers all in a random order every time. I've got the random password generator part done but I'm not sure how to restrict it to 2 lower case letters, 2 upper case letters, 3 special symbols and 3 numbers.
This is what I have so far:
import random
import string
lc_letter = ["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"]
uc_letter = ["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"]
symbols = ["!","@","#","$","%","^","&","*","(",")","_","+","=","-","/",">","<",",",".","?","\\"]
numbers = ["0","1","2","3","4","5","6","7","8","9"]
options = [lc_letter,uc_letter,symbols,numbers]
for i in range(10):
choice = random.choice(options)
digit = random.choice(choice)
print(digit, end = '')
An alternative approach that I will suggest is, Take 2 letters from uppercase, lowercase etc. and then shuffle resulting password using random.shuffle method.
Pick every needed characters first, then shuffle them:
from random import choice as rd
from random import shuffle
import string
lc_letter = ["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"]
uc_letter = ["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"]
symbols = ["!","@","#","$","%","^","&","*","(",")","_","+","=","-","/",">","<",",",".","?","\\"]
numbers = ["0","1","2","3","4","5","6","7","8","9"]
options = [
rd(lc_letter),
rd(lc_letter),
rd(uc_letter),
rd(uc_letter),
rd(symbols),
rd(symbols),
rd(symbols),
rd(numbers),
rd(numbers),
rd(numbers),
]
shuffle(options)
print(''.join(options))
You can use constants from string:
import random
import string
s = ""
for i in range(2):
s = s + random.choice(string.ascii_lowercase)
for i in range(2):
s = s + random.choice(string.ascii_uppercase)
for i in range(3):
s = s + random.choice(string.punctuation)
for i in range(3):
s = s + random.choice(string.digits)
s = ''.join(random.sample(s, 10))
print(s)
What you can actually do is make a list of length 10 like this:
dist = [0, 0, 1, 1, 2, 2, 2, 3, 3, 3]
This list represents the distribution of each index out of your options list.
For example, you put lowercase letters first in the option, and you have to pick 2 lowercase values, therefore there are 2 zeroes in the distribution list.
Now you can pick an index in the list:
idx = random.randint(0, len(dist))
Then, pick your choice from the list at: options[dist[idx]].
Lastly pop the value at idx from dist.
dist.pop(idx)
This will generate all the valid passwords with the same probability.
You can use random.choice, random.sample, and constants from the string module to obtain randomly generated passwords.
import random
import string
lc_letter = string.ascii_lowercase
uc_letter = string.ascii_uppercase
# Could use string.punctuation here, but it would be different
# as your list doesn't contain semicolons or colons,
# while string.punctuation does.
symbols = ["!","@","#","$","%","^","&","*","(",")","_","+","=","-","/",">","<",",",".","?","\\"]
numbers = string.digits
lc_selection = [random.choice(lc_letter) for _ in range(2)]
uc_selection = [random.choice(uc_letter) for _ in range(2)]
symbol_selection = [random.choice(symbols) for _ in range(3)]
number_selection = [random.choice(numbers) for _ in range(3)]
print(''.join(random.sample(lc_selection + uc_selection + symbol_selection + number_selection, 10)))
An in my opinion better version of Yevgeniy Kosmak's solution (the stand-alone config is clearer to see, the loop avoids code duplication, and using choices instead of choice avoids a loop).
import random
import string
config = [
(2, string.ascii_lowercase),
(2, string.ascii_uppercase),
(3, string.punctuation), # or use your '!@#$%^&*()_+=-/><,.?\\'
(3, string.digits),
]
picked = []
for k, options in config:
picked += random.choices(options, k=k)
random.shuffle(picked)
password = ''.join(picked)
print(password)