Alfie brown
Alfie brown

Reputation: 87

Python v3 ( Random password generator )

My question is: how to generate a random password with a length that varies from (8 to 12 characters) each time generated.

This is my code:

import string
import random

def randompassword():
    chars=string.ascii_uppercase + string.ascii_lowercase + string.digits
    size=8 
    return ''.join(random.choice(chars) for x in range(size,12))

print(randompassword())

Upvotes: 6

Views: 20281

Answers (6)

NYCeyes
NYCeyes

Reputation: 5659

There are nuances to this question and certain solutions may cause password weakness problems. Consider the following nuances along with the solution alternative.

  • Some answers employ string.printable, but this isn't a good idea since that contains whitespace characters. While they are not strictly illegal for passwords, you cannot easily see them and therefore cannot differentiate, say, a tab from several spaces (and so on). Below I only employ lowercase letters & uppercase letters, digits and punctuation characters.
  • Randomly choosing from a set of characters based on element-position isn't random since the cardinality of each included character-class isn't uniformly distributed: 26 Lowercase letters; 26 Uppercase letters; 10 Digits; 32 Punctuation characters. Therefore generated passwords are likely to have more letters than punctuation characters and digits; and more punctuation characters than digits; (and so on). So if random.choices() is used (as in other answers), one should also employ it's weights= and cum_weights= options, to eliminate aforementioned biases and even-out the distribution.
  • That said, I encourage use of Python's secrets module rather that its random module for this use case. From their documentation on random:

Warning: The pseudo-random generators of this module should not be used for security purposes. For security or cryptographic uses, see the secrets module.

Here is one functionally-oriented solution using Python-3. It uses secrets.choice() only. It doesn't totally solve the random problem (other nuances remain), but it does improve selection-distribution to reduces bias:

>>> import string, secrets

>>> char_classes = (string.ascii_lowercase,
                    string.ascii_uppercase,
                    string.digits,
                    string.punctuation)

>>> size = lambda: secrets.choice(range(8,13))                  # Chooses a password length.
>>> char = lambda: secrets.choice(secrets.choice(char_classes)) # Chooses one character, uniformly selected from each of the included character classes.
>>> pw   = lambda: ''.join([char() for _ in range(size())])     # Generates the variable-length password.

DEMO: Generate 10 variable-length password-strings using characters uniformly selected from each of our character classes:

>>> for i in range(1,11):
>>>    p = pw()
>>>    print('%i) %i chars :: %s' % (i,len(p),p))
 1) 11 chars :: IwWNEAUmnJt
 2) 10 chars :: ;N/'tO6RTv
 3)  8 chars :: l=5.2CDh
 4) 10 chars :: V0=I+A`t2Q
 5) 12 chars :: PQm8:f,#56"9
 6) 10 chars :: KOdx9~%r;F
 7) 11 chars :: <?67U8}3>F{
 8) 11 chars :: G$5y~3fE7o*
 9) 10 chars :: 70,|=Rexwn
10)  8 chars :: &31P^@cU

Finally, while we used the secrets module here, something similar could be done using numpy and numpy.random. I hope this helps!

Upvotes: 5

siebz0r
siebz0r

Reputation: 20329

Edit: As stated below the string.printable string contains characters that can cause issues when used for passwords. Instead of relying on this build-in set you're probably better off defining a custom set of usable characters. Don't forget about characters as space which are LHF to improving the strength of a password. Just be sure to handle heading/tailing spaces as the UI could potentially strip the input of a user preventing them from entering a valid password.

import random
import string

def randompassword():
    return ''.join([random.choice(string.printable) for _ in range(random.randint(8, 12))])

Upvotes: 1

Nikhil Sangy
Nikhil Sangy

Reputation: 11

string.ascii_letters #considers all the small case and large case alphabets. string.digits #considers 0 to 9 digits. string.punctuation #considers the special characters like symbols. random.choice #considers to randomly pick from the given data. range(random.randint(6, 12)) #considers to pick a random int range from the given data. print(generator_pw()) #prints random generated password.

import random, string

def generator_pw():
    pwd = string.ascii_letters + string.digits + string.punctuation
    return "".join(random.choice(pwd) for x in range(random.randint(6, 12)))

print(generator_pw())

Upvotes: 1

Denis
Denis

Reputation: 5271

size = 8; range(size, 12) always returns array [8,9,10,11], so you always get a password of length 4. Instead, determine the size of this particular password using randint ahead of time:

import string
import random

def randompassword():
  chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
  size = random.randint(8, 12)
  return ''.join(random.choice(chars) for x in range(size))

Upvotes: 16

user2737955
user2737955

Reputation:

I believe it's only printing 4 characters due tosize = 8 and range(size,12). This translates to range(8, 12) = 4 characters. You could increase the second number to allocate for a larger range to print random characters for like so

import string
import random

def randompassword():
    chars=string.ascii_uppercase + string.ascii_lowercase + string.digits
    size= 8
    return ''.join(random.choice(chars) for x in range(size,20))

print(randompassword())

Also be sure to check out python's random documentation here.

Upvotes: 1

Kirk Strauser
Kirk Strauser

Reputation: 30933

range(size,12) only returns numbers between size (which you've hardcoded to 8) and 12, so your passwords will only be 4 characters long. Make that ... for x in range(size).

Upvotes: 0

Related Questions