Chcę wygenerować ciąg znaków o rozmiarze N.
Powinien on składać się z liczb i wielkich liter angielskich, takich jak:
Jak mogę to osiągnąć w pythoniczny sposób?
Odpowiedź w jednej linii:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
lub nawet krócej, zaczynając od Pythona 3.6, używając random.choices()
:
''.join(random.choices(string.ascii_uppercase + string.digits, k=N))
Bezpieczniejsza kryptograficznie wersja; zobacz https://stackoverflow.com/a/23728630/2213647:.
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
W szczegółach, z czystą funkcją do dalszego wykorzystania:
>>> 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'
**Jak to działa?
Importujemy string
, moduł zawierający sekwencje zwykłych znaków ASCII, oraz random
, moduł zajmujący się generowaniem losowym.
String.ascii_uppercase + string.digits` po prostu konkatenuje listę znaków reprezentujących wielkie litery ASCII oraz cyfry:
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
Następnie używamy list comprehension, aby utworzyć listę 'n' elementów:
>>> 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']
W powyższym przykładzie używamy [
do utworzenia listy, ale nie w funkcji id_generator
, więc Python nie tworzy listy w pamięci, ale generuje elementy w locie, jeden po drugim (więcej na ten temat tutaj).
Zamiast prosić o utworzenie 'n' razy łańcucha elem
, poprosimy Pythona o utworzenie 'n' razy losowego znaku, wybranego z ciągu znaków:
>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'
Dlatego random.choice(chars) for _ in range(size)
naprawdę tworzy ciąg znaków size
. Znaków, które są losowo wybierane z 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']
Następnie po prostu łączymy je z pustym ciągiem, więc sekwencja staje się ciągiem:
>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
Prostszym, szybszym, ale nieco mniej losowym sposobem jest użycie random.sample
zamiast wybierania każdej litery osobno, Jeśli n-powtórzeń jest dozwolonych, powiększ swoją losową bazę o n razy np.
import random
import string
char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))
Uwaga: random.sample zapobiega ponownemu użyciu znaków, zwielokrotnienie rozmiaru zestawu znaków sprawia, że wielokrotne powtórzenia są możliwe, ale nadal są mniej prawdopodobne niż w przypadku czystego losowego wyboru. Jeśli wybierzemy ciąg o długości 6, i wybierzemy 'X' jako pierwszy znak, w przykładzie wyboru, prawdopodobieństwo otrzymania 'X' jako drugiego znaku jest takie samo jak prawdopodobieństwo otrzymania 'X' jako pierwszego znaku. W implementacji random.sample szanse na otrzymanie 'X' jako dowolnego kolejnego znaku są tylko 6/7 szans na otrzymanie go jako pierwszego znaku.
Myślałem, że nikt nie odpowiedział na to jeszcze lol! Ale hej, tutaj'jest mój własny go na to:
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))], "")