First, an important comment: the module documentation random
clearly states that this should not be used for security and encryption purposes, and suggests the use of module secrets
(available from Python 3.6).
That said, let’s see how to solve with both modules.
One detail: you’re always adding a capital letter and a lowercase letter, and a capital letter, and a lowercase letter, etc. This doesn’t seem random enough. Wouldn’t it be better to mix all the letters?
Also, from Python 3.6 you can use random.choices
(note the "Choices", plural), passing the amount of random elements you want to extract.
Then, to join all the letters in a single string, use join
, as indicated by the other replies.
As in your case the password has 16 characters, it would look like this:
from random import choices
minusculas = ['a','b','c','d','f','g','h']
maiusculas = ['A','B','C','D','F','G','H']
senha = ''.join(choices(minusculas + maiusculas, k=16))
Thus, the password gets a little more random than if you always switch one case with another lower case.
One detail is that the letters do not need to be in a list. In Python, strings are also iterable, so this could be how it works too:
minusculas = 'abcdefgh'
maiusculas = 'ABCDEFGH'
senha = ''.join(choices(minusculas + maiusculas, k=16))
If you are using Python < 3.6 you can simply join the two lists and call choice
several times:
from random import choice
minusculas = ['a','b','c','d','f','g','h']
maiusculas = ['A','B','C','D','F','G','H']
letras = maiusculas + minusculas
senha = []
for _ in range(16):
senha.append(choice(letras))
senha = ''.join(senha)
Or, using a comprehensilist on, much more succinct and pythonic:
senha = ''.join(choice(letras) for _ in range(16))
Of course there is still the chance that the generated password only has lowercase (or only uppercase), but it still seems better to me than to always have them alternated. Anyway, at the end we will see how to ensure this with the module secrets
.
But if the idea is in fact to alternate (always a capital and then a lowercase), there is no way, have to call choice
several times:
from random import choice
minusculas = ['a','b','c','d','f','g','h']
maiusculas = ['A','B','C','D','F','G','H']
senha = []
for _ in range(8): # iterando 8 vezes para que a senha tenha 16 caracteres
senha.append(choice(maiusculas))
senha.append(choice(minusculas))
senha = ''.join(senha)
Or, using a comprehensilist on, together with the module itertools
:
from random import choice
from itertools import chain
minusculas = ['a','b','c','d','f','g','h']
maiusculas = ['A','B','C','D','F','G','H']
senha = ''.join(chain.from_iterable((choice(maiusculas), choice(minusculas)) for _ in range(8)))
But if you did so just to "guarantee" that it will always have 8 upper and 8 lower case letters, one option would be to shuffle the list at the end, because at least they do not alternate (although the fact that you always generate with 8 of each makes the password more predictable than mixed everything, but anyway):
import random
senha = []
for _ in range(8): # iterando 8 vezes para que a senha tenha 16 caracteres
senha.append(random.choice(maiusculas))
senha.append(random.choice(minusculas))
random.shuffle(senha) # embaralhar a string, para as maiúsculas não ficarem alternadas com minúsculas
senha = ''.join(senha)
Module secrets
As already said at the beginning, the module random
is not suitable for generating passwords and any other uses involving encryption and security, and the documentation suggests the use of the module secrets
.
The form of use is very similar, so much so that there is a method choice
similar to existing in random
:
from secrets import choice
minusculas = ['a','b','c','d','f','g','h']
maiusculas = ['A','B','C','D','F','G','H']
letras = maiusculas + minusculas
senha = ''.join(choice(letras) for _ in range(16))
The problem is that there is still the possibility that the password only has lowercase (or only uppercase) letters - maybe that’s why you were switching? Finally, the documentation itself suggests a way around this:
while True:
senha = ''.join(choice(letras) for _ in range(16))
if (any(c.islower() for c in senha)
and any(c.isupper() for c in senha)): # se tiver pelo menos uma maiúscula e uma minúscula, interrompe o loop
break