The best way to write this "double-barreled list" in Python

The for loop on line 12 and one nested inside of it, I mean. I have met such situations more than once. I would use a list, but it doesn't seem to work here.

import random

import string

def password_generator():
    key = zip(string.digits, string.ascii_uppercase)

    cruft, x = str(random.random()).split('.')

    pw = ''

    for item in x:
        for element in key:
            if item in element:
                Q = random.random()
                if Q > 0.7:
                    pw += element[1].lower()
                else:
                    pw += element[1]

    print pw

      

Thank.

+3


source to share


4 answers


A list comprehension can be used here:

def pw_gen():
    key = zip(string.digits, string.ascii_uppercase)

    cruft, x = str(random.random()).split('.')

    def f(i,e):
      Q = random.random()
      if Q > 0.7:
        return e[1].lower()
      else:
        return e[1]

    return [ f(item,element) for item in x for element in key if item in element ]

      



Returns a list of characters. Use "".join( pw_gen() )

to convert to string.

+3


source


It seems to me that the difficult thing for you to do is that in the middle of the loop you get a random part. () <0.7. Make it a separate function, and it's easier to turn it into a list comprehension.



def f(str):
    if random.random()>0.7:
        return str.lower()
    else:
        return str

''.join([f(element[1]) for element in key for item in x if item in element])

      

+2


source


You can use itertools.product to combine the two, but I feel like this task can be simplified by using a higher level method from random.

symbols=string.ascii_uppercase[:10]
pw = ''
for i in range(15):
  letter = random.choice(symbols)
  if random.random() > 0.7:
    letter = letter.lower()
  pw += letter

      

Or even shorter:

symbols = (7*string.ascii_uppercase[:10] +
           3*string.ascii_lowercase[:10])
pw = ''.join(random.choice(symbols) for i in range(15))

      

The way it is constructed key

makes it a very inefficient lookup table. You can replace multiple lines to use a more efficient method:

key = dict(zip(string.digits, string.ascii_uppercase))
#...
for item in x:
    letter = key[item]

      

They all admittedly produce a fixed length password, and string conversions have a small chance of getting a shorter number. However, for the same reasons, the last figure was less random than the others.

+2


source


Your logic can be much simpler than using a list comprehension to replace the inner loop. This will be the equivalent of your code:

import random
import string
key = dict(zip(string.digits, string.ascii_uppercase))
cruft, x = str(random.random()).split('.', 1)
pw = ''
for item in x:
    if item in key: # This if is not required as all the single digits are present
        Q = random.random()
        if Q>0.7:
            pw += key[item].lower()
        else:
            pw += key[item]
print pw

      

However, I would advise you to go with a UUID if you really want the password to be unique and not required for easy conversion.If you want a better password generator (with alphanumeric and symbols) you can do something like this .

Please note that this is not an official python site and could be improved in many ways. As usual, this will be your challenge to shoot , I mean to use it in some way.

0


source







All Articles