Generazione di stringhe casuali con lettere maiuscole e cifre

Voglio generare una stringa di dimensione N.

Dovrebbe essere composta da numeri e lettere inglesi maiuscole come:

  • 6U1S75
  • 4Z4UKK
  • U911K4

Come posso ottenere questo in modo pitonico?

Soluzione

Risposta in una riga:

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

o anche più breve a partire da Python 3.6 usando random.choices():

''.join(random.choices(string.ascii_uppercase + string.digits, k=N))

Una versione crittograficamente più sicura; vedere https://stackoverflow.com/a/23728630/2213647:

''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))

In dettaglio, con una funzione pulita per un ulteriore riutilizzo:

>>> import string
>>> import random
>>> def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
...    return ''.join(random.choice(chars) for _ in range(size))
...
>>> id_generator()
'G5G74W'
>>> id_generator(3, "6793YUIO")
'Y3U'

**Come funziona?

Importiamo string, un modulo che contiene sequenze di caratteri ASCII comuni, e random, un modulo che si occupa della generazione casuale.

string.ascii_uppercase + string.digits si limita a concatenare la lista di caratteri che rappresentano i caratteri ASCII maiuscoli e le cifre:

>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

Poi usiamo una list comprehension per creare una lista di 'n' elementi:

>>> range(4) # range create a list of 'n' numbers
[0, 1, 2, 3]
>>> ['elem' for _ in range(4)] # we use range to create 4 times 'elem'
['elem', 'elem', 'elem', 'elem']

Nell'esempio sopra, usiamo [ per creare la lista, ma non lo facciamo nella funzione id_generator così Python non crea la lista in memoria, ma genera gli elementi al volo, uno per uno (maggiori informazioni su questo qui).

Invece di chiedere di creare 'n' volte la stringa elem, chiederemo a Python di creare 'n' volte un carattere casuale, scelto da una sequenza di caratteri:

>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'

Quindi random.choice(chars) for _ in range(size) sta davvero creando una sequenza di caratteri size. Caratteri che sono scelti a caso da chars:

>>> [random.choice('abcde') for _ in range(3)]
['a', 'b', 'b']
>>> [random.choice('abcde') for _ in range(3)]
['e', 'b', 'e']
>>> [random.choice('abcde') for _ in range(3)]
['d', 'a', 'c']

Poi li uniamo semplicemente con una stringa vuota in modo che la sequenza diventi una stringa:

>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
Commentari (27)

Un modo più semplice, più veloce ma leggermente meno casuale è quello di usare random.sample invece di scegliere ogni lettera separatamente, Se sono permesse n-ripetizioni, allargate la vostra base casuale di n volte, ad esempio

import random
import string

char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))

Nota: random.sample impedisce il riutilizzo dei caratteri, moltiplicando la dimensione del set di caratteri si rendono possibili ripetizioni multiple, ma sono ancora meno probabili di quanto lo siano in una scelta casuale pura. Se andiamo per una stringa di lunghezza 6, e scegliamo 'X' come primo carattere, nell'esempio di scelta, le probabilità di ottenere 'X' come secondo carattere sono le stesse di quelle di ottenere 'X' come primo carattere. Nell'implementazione random.sample, le probabilità di ottenere 'X' come qualsiasi carattere successivo sono solo 6/7 delle probabilità di ottenerlo come primo carattere

Commentari (10)

Pensavo che nessuno avesse ancora risposto a questo lol! Ma ehi, ecco il mio tentativo:

import random

def random_alphanumeric(limit):
    #ascii alphabet of all alphanumerals
    r = (range(48, 58) + range(65, 91) + range(97, 123))
    random.shuffle(r)
    return reduce(lambda i, s: i + chr(s), r[:random.randint(0, len(r))], "")
Commentari (2)