Generate password in python
You should use the secrets module to generate cryptographically safe passwords, which is available starting in Python 3.6. Adapted from the documentation:
import secrets
import string
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(20)) # for a 20-character password
For more information on recipes and best practices, see this section on recipes in the Python documentation. You can also consider adding string.punctuation
or even just using string.printable
for a wider set of characters.
Two recipes using the builtin secrets (python 3.6+)
1. secrets.token_urlsafe
This is much faster than the accepted answer. (see timings below)
import secrets
password = secrets.token_urlsafe(32)
Example output:
4EPn9Z7RE3l6jtCxEy7CPhia2EnYDEkE6N1O3-WnntU
The argument for token_urlsafe
is number of bytes. On average, one byte is 1.3 characters (base64 encoded).
2. Enforce amount of digits/upper characters etc
This is slighly modified copy from the docs of secrets. With this you have more fine grained control on how to generated passwords have to look. Of course, this is not fast option if you need to generate a lot of passwords.
- Forcing length to be 20 characters
- Forcing at least 4 lower case character
- Forcing at least 4 upper case characters
- Forcing at least 4 digits
- Special characters can be added to
alphabet
. In this example, there are just-
and_
added.
import string
import secrets
alphabet = string.ascii_letters + string.digits + '-_'
while True:
password = ''.join(secrets.choice(alphabet) for i in range(20))
if (sum(c.islower() for c in password) >=4
and sum(c.isupper() for c in password) >=4
and sum(c.isdigit() for c in password) >=4):
break
Example output:
HlxTm2fcFE54JA1I_Yp5
3. "I don't need the finer-grained control"
If considered speed, you can also drop the while-loop. In this case, it actually simplifies to gerrit's answer (but then you loose the finer-grained control):
import string
import secrets
alphabet = string.ascii_letters + string.digits + '-_'
password = ''.join(secrets.choice(alphabet) for i in range(20))
Speed comparison
1. secrets.token_urlsafe
1.62 µs ± 96.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
2. Enforce amount of digits/upper characters etc
107 µs ± 11.9 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
3. "I don't need the finer-grained control"
77.2 µs ± 9.31 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Speed comparison setup: python 3.8.5 64-bit on Win10, 43 characters in each password (=32 bytes for token_urlsafe).
For the crypto-PRNG folks out there:
def generate_temp_password(length):
if not isinstance(length, int) or length < 8:
raise ValueError("temp password must have positive length")
chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
from os import urandom
# original Python 2 (urandom returns str)
# return "".join(chars[ord(c) % len(chars)] for c in urandom(length))
# Python 3 (urandom returns bytes)
return "".join(chars[c % len(chars)] for c in urandom(length))
Note that for an even distribution, the chars
string length ought to be an integral divisor of 128; otherwise, you'll need a different way to choose uniformly from the space.