To bardzo popularne pytanie. Chciałbym, aby ekspert dodał swoje podejście do wyjątkowości tych liczb losowych dla 3 najlepszych odpowiedzi, tj. Prawdopodobieństwo kolizji dla zakresu wielkości łańcucha, powiedzmy od 6 do 16.
użytkownik
8
@ bufor Łatwo obliczyć liczbę możliwych kombinacji. 10 cyfr + 26 liter = 36 możliwych znaków, do potęgi 6 (długość łańcucha) wynosi około dwóch miliardów. Moją ogólną zasadą dla losowych wartości jest „jeśli wygenerowałbym wartości dla każdego człowieka na Ziemi, ile wartości mogliby oni mieć dla siebie?”. W takim przypadku byłoby to mniej niż jedna wartość na osobę, więc jeśli ma to na celu identyfikację użytkowników lub obiektów, to jest za mało znaków. Jedną z możliwości byłoby dodanie małych liter, co daje 62 ^ 6 = prawie 57 miliardów unikalnych wartości.
Blixt
1
I choć myślenie o populacji na świecie może wydawać się głupie, to tylko dlatego, że potrzebujesz ogromnego bufora dla potencjalnych kolizji. Zobacz problem urodzinowy: en.wikipedia.org/wiki/Birthday_problem
Następnie używamy rozumienia listy, aby utworzyć listę elementów „n”:
>>> 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 tworzenia listy, ale nie mamy id_generatorfunkcji, więc Python nie tworzy listy w pamięci, ale generuje elementy w locie, jeden po drugim (więcej o tym tutaj ).
Zamiast prosić o utworzenie „n” razy ciągu elem, poprosimy Pythona o utworzenie „n” razy losowego znaku, wybranego z sekwencji znaków:
Dlatego random.choice(chars) for _ in range(size)naprawdę tworzy sekwencję sizeznaków. Znaki wybierane losowo 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 pustym ciągiem, aby sekwencja stała 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'
@jorelli: To nie jest lista; to wyrażenie generatora.
Ignacio Vazquez-Abrams
2
@joreilli: W odpowiedzi dodałem krótką notatkę i link do bardziej szczegółowej odpowiedzi na temat iteracji, zrozumienia listy, generatorów i ewentualnie słowa kluczowego wydajności.
e-satis,
1
Chciałbym zamienić rangez xrange.
Dr Jan-Philip Gehrcke
1
Bardzo przydatne. Co ciekawe, Django używa tego fragmentu kodu do generowania haseł i tokenów CSRF. Chociaż należy wymienić randomz random.SystemRandom(): github.com/django/django/blob/...
użytkownik
1
@ Chiel92, random.sampletworzy próbki bez zamiany, innymi słowy, bez możliwości powtarzania znaków, co nie jest zgodne z wymaganiami PO. Nie sądzę, że byłoby to pożądane w przypadku większości aplikacji.
ontolog,
557
To pytanie o przepełnienie stosu jest obecnie najwyższym wynikiem Google dla „losowego ciągu Python”. Obecna najwyższa odpowiedź to:
''.join(random.choice(string.ascii_uppercase + string.digits)for _ in range(N))
Jest to doskonała metoda, ale losowy PRNG nie jest kryptograficznie bezpieczny. Zakładam, że wiele osób badających to pytanie będzie chciało generować losowe ciągi do szyfrowania lub haseł. Możesz to zrobić bezpiecznie, wprowadzając niewielką zmianę w powyższym kodzie:
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits)for _ in range(N))
Używanie random.SystemRandom()zamiast przypadkowych zastosowań / dev / urandom na maszynach * nix i CryptGenRandom()Windows. Są to kryptograficznie bezpieczne PRNG. Używanie random.choicezamiast random.SystemRandom().choiceaplikacji wymagającej bezpiecznego PRNG może być potencjalnie niszczycielskie, a biorąc pod uwagę popularność tego pytania, założę się, że błąd popełniono już wiele razy.
Jeśli używasz Python3.6 lub nowszego, możesz użyć nowego modułu sekretów , jak wspomniano w odpowiedzi MSeifert :
''.join(secrets.choice(string.ascii_uppercase + string.digits)for _ in range(N))
Tak, oficjalna biblioteka standardowa dla randomostrzega: „ Ostrzeżenie : Pseudolosowych generatorów tego modułu nie należy używać do celów bezpieczeństwa. Użyj os.urandom () lub SystemRandom, jeśli potrzebujesz kryptograficznie bezpiecznego generatora liczb pseudolosowych. „ Oto ref: random.SystemRandom i os.urandom
lord63. j
4
Świetna odpowiedź. Mała uwaga: Zmieniłeś to, string.uppercaseco może prowadzić do nieoczekiwanych wyników w zależności od zestawu ustawień regionalnych. Użycie string.ascii_uppercase(lub string.ascii_letters + string.digitsdla base62 zamiast base36) jest bezpieczniejsze w przypadkach, w których występuje kodowanie.
Blixt
mała uwaga - lepiej użyć xrangezamiast tego, rangeże ten drugi generuje listę w pamięci, podczas gdy ten pierwszy tworzy iterator.
guyarad
2
czy losowe żądło będzie zawsze wyjątkowe? chciałem użyć klucza podstawowego.
shakthydoss
3
@shakthydoss: nie. Może zwrócić „AAA000”, który jest ciągiem losowym, a następnie „AAA000”, który jest także ciągiem losowym. Musisz jawnie dodać czek na niepowtarzalność.
Jeżeli UUID są w porządku dla swoich potrzeb, korzystać z wbudowanego w UUID opakowaniu.
Rozwiązanie jednoliniowe:
import uuid; uuid.uuid4().hex.upper()[0:6]
W wersji głębokiej:
Przykład:
import uuid
uuid.uuid4()#uuid4 => full random uuid# Outputs something like: UUID('0172fc9a-1dac-4414-b88d-6b9a6feb91ea')
Jeśli potrzebujesz dokładnie swojego formatu (na przykład „6U1S75”), możesz to zrobić w następujący sposób:
import uuid
def my_random_string(string_length=10):"""Returns a random string of length string_length."""
random = str(uuid.uuid4())# Convert UUID format to a Python string.
random = random.upper()# Make all characters uppercase.
random = random.replace("-","")# Remove the UUID '-'.return random[0:string_length]# Return the random string.print(my_random_string(6))# For example, D9E50C
+1 Za przemyślenie pytania. Być może mógłbyś krótko wyjaśnić różnicę między uuid1 a uuid4.
Thomas Ahle
1
Jeśli zrobię uuid1 trzy razy z rzędu, dostaję: d161fd16-ab0f-11e3-9314-00259073e4a8, d3535b56-ab0f-11e3-9314-00259073e4a8, d413be32-ab0f-11e3-9314-00259073e4a8, co wydaje się podejrzane (podobne) pierwsze 8 znaków różni się, a pozostałe są takie same). Nie jest tak w przypadku uuid4
Chase Roberts
9
uui1: Wygeneruj identyfikator UUID na podstawie identyfikatora hosta, numeru sekwencji i bieżącej godziny. uuid4: Wygeneruj losowy UUID.
Bijan
7
Jeśli chcesz pominąć rzutowanie ciągów i zamianę łączników, możesz po prostu wywołać my_uuid.get_hex () lub uuid.uuid4 (). Get_hex (), a to zwróci ciąg wygenerowany z identyfikatora użytkownika, który nie ma łączników.
dshap
8
Czy to dobry pomysł, aby obciąć UUID? W zależności od tego, jak małe string_lengthjest, prawdopodobieństwo zderzenia może stanowić problem.
użytkownik
44
Prostszym, szybszym, ale nieco mniej losowym sposobem jest użycie random.samplezamiast wybierania każdej litery osobno. Jeśli dozwolonych jest n-powtórzeń, powiększ swoją losowość 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, pomnożenie rozmiaru zestawu znaków umożliwia wielokrotne powtórzenia, ale nadal są one mniej prawdopodobne niż w przypadku losowego wyboru. Jeśli zdecydujemy się na ciąg o długości 6 i wybieramy „X” jako pierwszy znak, w przykładzie wyboru szanse na uzyskanie „X” dla drugiego znaku są takie same, jak szanse na uzyskanie „X” jako pierwsza postać. W implementacji random.sample szanse na uzyskanie „X” jako każdej kolejnej postaci mają tylko 6/7 szansy na uzyskanie jej jako pierwszej postaci
Ten sposób nie jest zły, ale nie jest tak losowy, jak wybieranie każdej postaci osobno, ponieważ samplenigdy nie zobaczysz tej samej postaci dwa razy na liście. Oczywiście, że zawiedzie na Nwięcej niż 36.
bobince
dla danego przypadku użycia (jeśli żadne powtórzenie nie jest w porządku) powiem, że jest to nadal najlepsze rozwiązanie.
Anurag Uniyal
3
Jeden z przykładów ma powtórzenie, więc wątpię, czy chce zabronić powtórzeń.
Mark Byers
5
Jeśli zapobiega random.sample postaci ponownego wykorzystania, mnożąc rozmiar zestawu znaków sprawia, że wiele powtórzeń to możliwe , ale są jeszcze mniej prawdopodobne, to są one w czystej losowego wyboru. Jeśli zdecydujemy się na ciąg o długości 6 i wybieramy „X” jako pierwszy znak, w przykładzie wyboru szanse na uzyskanie „X” dla drugiego znaku są takie same, jak szanse na uzyskanie „X” jako pierwsza postać. W implementacji random.sample szanse na uzyskanie „X” jako każdej kolejnej postaci mają tylko 5/6 szansy na uzyskanie jej jako pierwszej postaci.
pcurry
1
Szansa na powtórzenie określonej postaci spada wraz z przejściem przez wygenerowany ciąg. Generowanie ciągu 6 znaków z 26 wielkich liter plus 10 cyfr, losowy wybór każdego znaku niezależnie, każdy określony ciąg występuje z częstotliwością 1 / (36 ^ 6). Szansa na wygenerowanie „FU3WYE” i „XXXXXX” jest taka sama. W przykładowej implementacji szansa na wygenerowanie „XXXXXX” wynosi (1 / (36 ^ 6)) * ((6/6) * (5/6) * (4/6) * (3/6) * (2 / 6) * (1/6)) z powodu niewymiennej funkcji random.sample. „XXXXXX” jest 324 razy mniej prawdopodobne w przykładowej implementacji.
pcurry
32
import uuid
lowercase_str = uuid.uuid4().hex
lowercase_str jest wartością losową jak 'cea8b32e00934aaea8c005a35d85a5c0'
uppercase_str = lowercase_str.upper()
uppercase_str jest 'CEA8B32E00934AAEA8C005A35D85A5C0'
@Yajo: nie, nie chcesz wycinać wartości szesnastkowej. Usuwasz entropię w porównaniu z pełną sekwencją wielkich liter i cyfr. Być może zamiast tego kodowana jest wartość base32 (nieco zmniejszona entropia, z 36 ** n do 32 ** n, wciąż lepsza niż 16 ** n).
Martijn Pieters
19
Szybszym, łatwiejszym i bardziej elastycznym sposobem na to jest użycie strgenmodułu ( pip install StringGenerator).
Wygeneruj losowy ciąg 6 znaków z dużymi literami i cyframi:
''.join(random.choice(string.ascii_uppercase + string.digits)for _ in range(N))
może nie zawierać cyfr (lub wielkich liter).
strgenczas programowania jest krótszy niż którekolwiek z powyższych rozwiązań. Rozwiązanie firmy Ignacio zapewnia najszybsze działanie w czasie wykonywania i jest właściwą odpowiedzią przy użyciu biblioteki standardowej Python. Ale prawie nigdy nie użyjesz go w tej formie. Będziesz chciał użyć SystemRandom (lub awaryjne, jeśli nie jest dostępne), upewnij się, że wymagane zestawy znaków są reprezentowane, użyj Unicode (lub nie), upewnij się, że kolejne wywołania generują unikatowy ciąg, użyj podzbioru jednej z klas znaków modułu ciągów, itd. To wszystko wymaga znacznie więcej kodu niż w podanych odpowiedziach. Różne próby uogólnienia rozwiązania mają ograniczenia, które często rozwiązują się z większą zwięzłością i mocą ekspresji przy użyciu prostego języka szablonów.
Począwszy od Pythona 3.6, powinieneś używać secretsmodułu, jeśli chcesz go kryptograficznie zabezpieczyć zamiast randommodułu (w przeciwnym razie odpowiedź jest identyczna z odpowiedzią @Ignacio Vazquez-Abrams):
from secrets import choice
import string
''.join([choice(string.ascii_uppercase + string.digits)for _ in range(N)])
Jedna dodatkowa uwaga: zrozumienie listy jest szybsze w przypadku str.joinniż użycia wyrażenia generatora!
Jest to miłe, chociaż będzie używać tylko „AF”, a nie „A-Z”. Ponadto kod staje się trochę mniej przyjemny, gdy parametryczny N.
Thomas Ahle
9
Jeśli potrzebujesz ciągu losowego zamiast pseudolosowego , powinieneś użyć go os.urandomjako źródła
from os import urandom
from itertools import islice, imap, repeat
import string
def rand_string(length=5):
chars = set(string.ascii_uppercase + string.digits)
char_gen =(c for c in imap(urandom, repeat(1))if c in chars)return''.join(islice(char_gen,None, length))
Jak to os.urandomnie jest pseudolosowe? Być może używa lepszego algorytmu do generowania liczb, które są bardziej losowe, ale nadal jest pseudolosowy.
Tyilo,
@Tyilo, zdaję sobie sprawę z różnicy między /dev/randomi /dev/urandom. Problem polega na tym, że /dev/randomblokuje się, gdy entropia jest niewystarczająca, co ogranicza jej przydatność. Na jeden raz pad/dev/urandom nie jest wystarczająco dobry, ale myślę, że jest lepszy niż pseudolosowy.
John La Rooy,
1
Powiedziałbym, że jedno /dev/randomi drugie /dev/urandomjest pseudolosowe, ale może zależeć od twojej definicji.
Tyilo,
9
Myślałem, że nikt jeszcze nie odpowiedział na to lol! Ale hej, oto moje własne:
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))],"")
Nie będę głosować za tym, ale myślę, że jest to zbyt skomplikowane, aby wykonać tak proste zadanie. Zwrotem jest potwór. Prosty jest lepszy niż złożony.
Carl Smith
12
@CarlSmith, prawda, moje rozwiązanie wydaje się nieco przesadne w stosunku do zadania, ale zdawałem sobie sprawę z innych prostszych rozwiązań i po prostu chciałem znaleźć alternatywną drogę do dobrej odpowiedzi. Bez wolności kreatywność jest w niebezpieczeństwie, dlatego napisałem ją.
nemesisfixx
7
Ta metoda jest nieco szybsza i nieco bardziej irytująca niż metoda random.choice (), którą opublikował Ignacio.
Wykorzystuje naturę algorytmów pseudolosowych, a banki bitowe i przesuwne są szybsze niż generowanie nowej liczby losowej dla każdego znaku.
# must be length 32 -- 5 bits -- the question didn't specify using the full set# of uppercase letters ;)
_ALPHABET ='ABCDEFGHJKLMNPQRSTUVWXYZ23456789'def generate_with_randbits(size=32):def chop(x):while x:yield x &31
x = x >>5return''.join(_ALPHABET[x]for x in chop(random.getrandbits(size *5))).ljust(size,'A')
... stwórz generator, który pobiera 5 liczb bitowych na raz 0..31, dopóki nie zostanie żaden
... dołącz () wyniki generatora na losowej liczbie z odpowiednimi bitami
W przypadku Timeit dla łańcuchów 32-znakowych czas był następujący:
Ale ten wariant zmusi wszystkie postacie do bycia innym. I to nie zadziała, jeśli N jest większy niż len (string.ascii_uppercase + string.digits)
MarSoft
3
Dla tych, którzy lubią funkcjonalny python:
from itertools import imap, starmap, islice, repeat
from functools import partial
from string import letters, digits, join
from random import choice
join_chars = partial(join, sep='')
identity =lambda o: o
def irand_seqs(symbols=join_chars((letters, digits)), length=6, join=join_chars, select=choice, breakup=islice):""" Generates an indefinite sequence of joined random symbols each of a specific length
:param symbols: symbols to select,
[defaults to string.letters + string.digits, digits 0 - 9, lower and upper case English letters.]
:param length: the length of each sequence,
[defaults to 6]
:param join: method used to join selected symbol,
[defaults to ''.join generating a string.]
:param select: method used to select a random element from the giving population.
[defaults to random.choice, which selects a single element randomly]
:return: indefinite iterator generating random sequences of giving [:param length]
>>> from tools import irand_seqs
>>> strings = irand_seqs()
>>> a = next(strings)
>>> assert isinstance(a, (str, unicode))
>>> assert len(a) == 6
>>> assert next(strings) != next(strings)
"""return imap(join, starmap(breakup, repeat((imap(select, repeat(symbols)),None, length))))
Generuje nieokreślony [nieskończony] iterator, połączonych losowych sekwencji, najpierw generując nieokreśloną sekwencję losowo wybranego symbolu z puli, a następnie dzieląc tę sekwencję na części długości, które są następnie łączone, powinien działać z dowolną sekwencją, która obsługuje getitem , domyślnie po prostu generuje losową sekwencję liter alfanumerycznych, chociaż można łatwo modyfikować, aby wygenerować inne rzeczy:
Jak wspomnieli inni, jeśli potrzebujesz większego bezpieczeństwa, ustaw odpowiednią funkcję wyboru:
>>>from random importSystemRandom>>> rand_strs = irand_seqs(select=SystemRandom().choice)'QsaDxQ'
domyślnym selektorem jest to, że choicemoże wybrać ten sam symbol wiele razy dla każdej porcji, jeśli zamiast tego chcesz, aby ten sam element był wybrany najwyżej raz dla każdej porcji, możliwe jest jedno użycie:
używamy samplejako naszego selektora, aby dokonać pełnego wyboru, więc fragmenty mają w rzeczywistości długość 1, a aby się połączyć, po prostu wywołujemy, nextktóry pobiera następny całkowicie wygenerowany fragment, pod warunkiem, że ten przykład wydaje się trochę niewygodny i jest ...
import string, random
passkey=''for x in range(8):if random.choice([1,2])==1:
passkey += passkey.join(random.choice(string.ascii_uppercase))else:
passkey += passkey.join(random.choice(string.digits))print passkey
(2) Jeśli później chcesz dołączyć małe litery do klucza, zadziała to również:
import string, random
passkey=''for x in range(8):if random.choice([1,2])==1:
passkey += passkey.join(random.choice(string.ascii_letters))else:
passkey += passkey.join(random.choice(string.digits))print passkey
>>>import random
>>> str =[]>>> chars ='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'>>> num = int(raw_input('How long do you want the string to be? '))How long do you want the string to be?10>>>for k in range(1, num+1):... str.append(random.choice(chars))...>>> str ="".join(str)>>> str
'tm2JUQ04CK'
random.choiceFunkcja wybiera losowy wpis w liście. Tworzysz także listę, aby móc dołączyć znak do forinstrukcji. Na końcu jest [„t”, „m”, „2”, „J”, „U”, „Q”, „0”, „4”, „C”, „K”], ale str = "".join(str)ujęcia dbaj o to, zostawiając cię z 'tm2JUQ04CK'.
Fajnie, ale możesz użyć range(num)zamiast tego, a str może być łańcuchem str += random.choice(chars).
sashk
2
import string
from random import*
characters = string.ascii_letters + string.punctuation + string.digits
password ="".join(choice(characters)for x in range(randint(8,16)))print password
Chociaż ten kod może odpowiedzieć na pytanie, dostarczenie dodatkowego kontekstu dotyczącego tego, dlaczego i / lub jak odpowiada na pytanie, znacznie poprawiłoby jego długoterminową wartość. Proszę edytować swoje odpowiedzi, aby dodać trochę wyjaśnień.
Toby Speight
2
import random
q=2
o=1
list =[r'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','s','0','1','2','3','4','5','6','7','8','9','0']while(q>o):print("")for i in range(1,128):
x=random.choice(list)print(x,end="")
Tutaj długość łańcucha można zmienić dla pętli, tj. Dla i w zakresie (1, długość) Jest to prosty algorytm, który jest łatwy do zrozumienia. używa listy, więc możesz odrzucić niepotrzebne znaki.
import string
import random
character = string.lowercase + string.uppercase + string.digits + string.punctuation
char_len = len(character)# you can specify your password length here
pass_len = random.randint(10,20)
password =''for x in range(pass_len):
password = password + character[random.randint(0,char_len-1)]print password
def randStr_2(chars:str, length:int)-> str:return''.join(random.choice(chars)for i in range(chars))
Benchmark:
from timeit import timeit
setup ="""
import os, subprocess, time, string, random, math
def randStr_1(letters:str, length:int) -> str:
letters *= math.ceil(length / len(letters))
letters = letters[0:length]
letters = list(letters)
random.shuffle(letters)
return ''.join(letters)
def randStr_2(letters:str, length:int) -> str:
return ''.join(random.choice(letters) for i in range(length))
"""print('Method 1 vs Method 2',', run 10 times each.')for length in[100,1000,10000,50000,100000,500000,1000000]:print(length,'characters:')
eff1 = timeit("randStr_1(string.ascii_letters, {})".format(length), setup=setup, number=10)
eff2 = timeit("randStr_2(string.ascii_letters, {})".format(length), setup=setup, number=10)print('\t{}s : {}s'.format(round(eff1,6), round(eff2,6)))print('\tratio = {} : {}\n'.format(eff1/eff1, round(eff2/eff1,2)))
Wynik :
Method1 vs Method2, run 10 times each.100 characters:0.001411s:0.00179s
ratio =1.0:1.271000 characters:0.013857s:0.017603s
ratio =1.0:1.2710000 characters:0.13426s:0.151169s
ratio =1.0:1.1350000 characters:0.709403s:0.855136s
ratio =1.0:1.21100000 characters:1.360735s:1.674584s
ratio =1.0:1.23500000 characters:6.754923s:7.160508s
ratio =1.0:1.061000000 characters:11.232965s:14.223914s
ratio =1.0:1.27
Przeszedłem przez prawie wszystkie odpowiedzi, ale żadna z nich nie wygląda na łatwiejszą. Sugeruję wypróbowanie biblioteki passgen, która jest zwykle używana do tworzenia losowych haseł.
Możesz generować losowe ciągi znaków o wybranej długości, interpunkcji, cyfrach, literach i wielkości liter .
import string, random
lower = string.ascii_lowercase
upper = string.ascii_uppercase
digits = string.digits
special ='!"£$%^&*.,@#/?'def rand_pass(l=4, u=4, d=4, s=4):
p =[][p.append(random.choice(lower))for x in range(l)][p.append(random.choice(upper))for x in range(u)][p.append(random.choice(digits))for x in range(d)][p.append(random.choice(special))for x in range(s)]
random.shuffle(p)return"".join(p)print(rand_pass())# @5U,@A4yIZvnp%51
Odpowiedzi:
Odpowiedź w jednym wierszu:
lub nawet krócej, zaczynając od Pythona 3.6, używając
random.choices()
:Wersja kryptograficznie bezpieczniejsza; patrz https://stackoverflow.com/a/23728630/2213647 :
Szczegółowo, z czystą funkcją do dalszego wykorzystania:
Jak to działa ?
Importujemy
string
moduł zawierający sekwencje typowych znaków ASCII orazrandom
moduł zajmujący się generowaniem losowym.string.ascii_uppercase + string.digits
po prostu łączy listę znaków reprezentujących wielkie znaki i cyfry ASCII:Następnie używamy rozumienia listy, aby utworzyć listę elementów „n”:
W powyższym przykładzie używamy
[
do tworzenia listy, ale nie mamyid_generator
funkcji, więc Python nie tworzy listy w pamięci, ale generuje elementy w locie, jeden po drugim (więcej o tym tutaj ).Zamiast prosić o utworzenie „n” razy ciągu
elem
, poprosimy Pythona o utworzenie „n” razy losowego znaku, wybranego z sekwencji znaków:Dlatego
random.choice(chars) for _ in range(size)
naprawdę tworzy sekwencjęsize
znaków. Znaki wybierane losowo zchars
:Następnie po prostu łączymy je pustym ciągiem, aby sekwencja stała się ciągiem:
źródło
range
zxrange
.random
zrandom.SystemRandom()
: github.com/django/django/blob/...random.sample
tworzy próbki bez zamiany, innymi słowy, bez możliwości powtarzania znaków, co nie jest zgodne z wymaganiami PO. Nie sądzę, że byłoby to pożądane w przypadku większości aplikacji.To pytanie o przepełnienie stosu jest obecnie najwyższym wynikiem Google dla „losowego ciągu Python”. Obecna najwyższa odpowiedź to:
Jest to doskonała metoda, ale losowy PRNG nie jest kryptograficznie bezpieczny. Zakładam, że wiele osób badających to pytanie będzie chciało generować losowe ciągi do szyfrowania lub haseł. Możesz to zrobić bezpiecznie, wprowadzając niewielką zmianę w powyższym kodzie:
Używanie
random.SystemRandom()
zamiast przypadkowych zastosowań / dev / urandom na maszynach * nix iCryptGenRandom()
Windows. Są to kryptograficznie bezpieczne PRNG. Używanierandom.choice
zamiastrandom.SystemRandom().choice
aplikacji wymagającej bezpiecznego PRNG może być potencjalnie niszczycielskie, a biorąc pod uwagę popularność tego pytania, założę się, że błąd popełniono już wiele razy.Jeśli używasz Python3.6 lub nowszego, możesz użyć nowego modułu sekretów , jak wspomniano w odpowiedzi MSeifert :
Dokumenty modułu omawiają również wygodne sposoby generowania bezpiecznych tokenów i najlepszych praktyk .
źródło
random
ostrzega: „ Ostrzeżenie : Pseudolosowych generatorów tego modułu nie należy używać do celów bezpieczeństwa. Użyj os.urandom () lub SystemRandom, jeśli potrzebujesz kryptograficznie bezpiecznego generatora liczb pseudolosowych. „ Oto ref: random.SystemRandom i os.urandomstring.uppercase
co może prowadzić do nieoczekiwanych wyników w zależności od zestawu ustawień regionalnych. Użyciestring.ascii_uppercase
(lubstring.ascii_letters + string.digits
dla base62 zamiast base36) jest bezpieczniejsze w przypadkach, w których występuje kodowanie.xrange
zamiast tego,range
że ten drugi generuje listę w pamięci, podczas gdy ten pierwszy tworzy iterator.Wystarczy użyć wbudowanego interfejsu użytkownika Pythona:
Jeżeli UUID są w porządku dla swoich potrzeb, korzystać z wbudowanego w UUID opakowaniu.
Rozwiązanie jednoliniowe:
import uuid; uuid.uuid4().hex.upper()[0:6]
W wersji głębokiej:
Przykład:
Jeśli potrzebujesz dokładnie swojego formatu (na przykład „6U1S75”), możesz to zrobić w następujący sposób:
źródło
string_length
jest, prawdopodobieństwo zderzenia może stanowić problem.Prostszym, szybszym, ale nieco mniej losowym sposobem jest użycie
random.sample
zamiast wybierania każdej litery osobno. Jeśli dozwolonych jest n-powtórzeń, powiększ swoją losowość n razy np.Uwaga: random.sample zapobiega ponownemu użyciu znaków, pomnożenie rozmiaru zestawu znaków umożliwia wielokrotne powtórzenia, ale nadal są one mniej prawdopodobne niż w przypadku losowego wyboru. Jeśli zdecydujemy się na ciąg o długości 6 i wybieramy „X” jako pierwszy znak, w przykładzie wyboru szanse na uzyskanie „X” dla drugiego znaku są takie same, jak szanse na uzyskanie „X” jako pierwsza postać. W implementacji random.sample szanse na uzyskanie „X” jako każdej kolejnej postaci mają tylko 6/7 szansy na uzyskanie jej jako pierwszej postaci
źródło
sample
nigdy nie zobaczysz tej samej postaci dwa razy na liście. Oczywiście, że zawiedzie naN
więcej niż36
.lowercase_str
jest wartością losową jak'cea8b32e00934aaea8c005a35d85a5c0'
uppercase_str
jest'CEA8B32E00934AAEA8C005A35D85A5C0'
źródło
uppercase_str[:N+1]
Szybszym, łatwiejszym i bardziej elastycznym sposobem na to jest użycie
strgen
modułu (pip install StringGenerator
).Wygeneruj losowy ciąg 6 znaków z dużymi literami i cyframi:
Uzyskaj unikalną listę:
Gwarancja jednego „specjalnego” znaku w ciągu:
Losowy kolor HTML:
itp.
Musimy mieć świadomość, że to:
może nie zawierać cyfr (lub wielkich liter).
strgen
czas programowania jest krótszy niż którekolwiek z powyższych rozwiązań. Rozwiązanie firmy Ignacio zapewnia najszybsze działanie w czasie wykonywania i jest właściwą odpowiedzią przy użyciu biblioteki standardowej Python. Ale prawie nigdy nie użyjesz go w tej formie. Będziesz chciał użyć SystemRandom (lub awaryjne, jeśli nie jest dostępne), upewnij się, że wymagane zestawy znaków są reprezentowane, użyj Unicode (lub nie), upewnij się, że kolejne wywołania generują unikatowy ciąg, użyj podzbioru jednej z klas znaków modułu ciągów, itd. To wszystko wymaga znacznie więcej kodu niż w podanych odpowiedziach. Różne próby uogólnienia rozwiązania mają ograniczenia, które często rozwiązują się z większą zwięzłością i mocą ekspresji przy użyciu prostego języka szablonów.Jest na PyPI:
Ujawnienie: Jestem autorem modułu strgen.
źródło
Począwszy od Pythona 3.6, powinieneś używać
secrets
modułu, jeśli chcesz go kryptograficznie zabezpieczyć zamiastrandom
modułu (w przeciwnym razie odpowiedź jest identyczna z odpowiedzią @Ignacio Vazquez-Abrams):Jedna dodatkowa uwaga: zrozumienie listy jest szybsze w przypadku
str.join
niż użycia wyrażenia generatora!źródło
Na podstawie innej odpowiedzi przepełnienia stosu, najlżejszy sposób na utworzenie losowego ciągu i losowej liczby szesnastkowej , lepsza wersja niż zaakceptowana odpowiedź to:
o wiele szybciej.
źródło
N
.Jeśli potrzebujesz ciągu losowego zamiast pseudolosowego , powinieneś użyć go
os.urandom
jako źródłaźródło
os.urandom
nie jest pseudolosowe? Być może używa lepszego algorytmu do generowania liczb, które są bardziej losowe, ale nadal jest pseudolosowy./dev/random
i/dev/urandom
. Problem polega na tym, że/dev/random
blokuje się, gdy entropia jest niewystarczająca, co ogranicza jej przydatność. Na jeden raz pad/dev/urandom
nie jest wystarczająco dobry, ale myślę, że jest lepszy niż pseudolosowy./dev/random
i drugie/dev/urandom
jest pseudolosowe, ale może zależeć od twojej definicji.Myślałem, że nikt jeszcze nie odpowiedział na to lol! Ale hej, oto moje własne:
źródło
Ta metoda jest nieco szybsza i nieco bardziej irytująca niż metoda random.choice (), którą opublikował Ignacio.
Wykorzystuje naturę algorytmów pseudolosowych, a banki bitowe i przesuwne są szybsze niż generowanie nowej liczby losowej dla każdego znaku.
... stwórz generator, który pobiera 5 liczb bitowych na raz 0..31, dopóki nie zostanie żaden
... dołącz () wyniki generatora na losowej liczbie z odpowiednimi bitami
W przypadku Timeit dla łańcuchów 32-znakowych czas był następujący:
... ale w przypadku ciągów 64 znaków randbits przegrywa;)
Prawdopodobnie nigdy nie zastosowałbym tego podejścia w kodzie produkcyjnym, chyba że naprawdę nie lubiłem moich współpracowników.
edycja: zaktualizowano, aby pasowało do pytania (tylko wielkie litery i cyfry), i używa operatorów bitowych & i >> zamiast% i //
źródło
Zrobiłbym to w ten sposób:
Lub tylko:
źródło
Użyj funkcji random.choice () Numpy
Dokumentacja znajduje się tutaj http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.random.choice.html
źródło
Czasami 0 (zero) i O (litera O) może być mylące. Więc używam
źródło
poniższa logika nadal generuje losową próbkę o długości 6 znaków
Nie ma potrzeby mnożenia przez 6
źródło
Dla tych, którzy lubią funkcjonalny python:
Generuje nieokreślony [nieskończony] iterator, połączonych losowych sekwencji, najpierw generując nieokreśloną sekwencję losowo wybranego symbolu z puli, a następnie dzieląc tę sekwencję na części długości, które są następnie łączone, powinien działać z dowolną sekwencją, która obsługuje getitem , domyślnie po prostu generuje losową sekwencję liter alfanumerycznych, chociaż można łatwo modyfikować, aby wygenerować inne rzeczy:
na przykład, aby wygenerować losowe krotki cyfr:
jeśli nie chcesz używać następnej generacji, możesz po prostu sprawić, że będzie to możliwe:
jeśli chcesz generować sekwencję w locie, po prostu ustaw dołącz do tożsamości.
Jak wspomnieli inni, jeśli potrzebujesz większego bezpieczeństwa, ustaw odpowiednią funkcję wyboru:
domyślnym selektorem jest to, że
choice
może wybrać ten sam symbol wiele razy dla każdej porcji, jeśli zamiast tego chcesz, aby ten sam element był wybrany najwyżej raz dla każdej porcji, możliwe jest jedno użycie:używamy
sample
jako naszego selektora, aby dokonać pełnego wyboru, więc fragmenty mają w rzeczywistości długość 1, a aby się połączyć, po prostu wywołujemy,next
który pobiera następny całkowicie wygenerowany fragment, pod warunkiem, że ten przykład wydaje się trochę niewygodny i jest ...źródło
(1) To da ci wszystkie czapki i liczby:
(2) Jeśli później chcesz dołączyć małe litery do klucza, zadziała to również:
źródło
to jest odpowiedź Anurag Uniyal i coś, nad czym pracowałem nad sobą.
źródło
random.choice
Funkcja wybiera losowy wpis w liście. Tworzysz także listę, aby móc dołączyć znak dofor
instrukcji. Na końcu jest [„t”, „m”, „2”, „J”, „U”, „Q”, „0”, „4”, „C”, „K”], alestr = "".join(str)
ujęcia dbaj o to, zostawiając cię z'tm2JUQ04CK'
.Mam nadzieję że to pomoże!
źródło
range(num)
zamiast tego, a str może być łańcuchemstr += random.choice(chars)
.źródło
Tutaj długość łańcucha można zmienić dla pętli, tj. Dla i w zakresie (1, długość) Jest to prosty algorytm, który jest łatwy do zrozumienia. używa listy, więc możesz odrzucić niepotrzebne znaki.
źródło
Prosty:
źródło
Chciałbym zasugerować następną opcję:
Tryb paranoiczny:
źródło
Dwie metody:
Wynik :
Wydajność pierwszej metody jest lepsza.
źródło
Przeszedłem przez prawie wszystkie odpowiedzi, ale żadna z nich nie wygląda na łatwiejszą. Sugeruję wypróbowanie biblioteki passgen, która jest zwykle używana do tworzenia losowych haseł.
Możesz generować losowe ciągi znaków o wybranej długości, interpunkcji, cyfrach, literach i wielkości liter .
Oto kod twojej sprawy:
źródło
Generuj losowe 16-bajtowe identyfikatory zawierające litery, cyfry, „_” i „-”
os.urandom(16).translate((f'{string.ascii_letters}{string.digits}-_'*4).encode('ascii'))
źródło
źródło
Uznałem, że jest to prostsze i czystsze.
Po prostu zmień 64, aby zmienić długość, zmień CharacterPool, aby zrobić tylko alfabet, cyfrę lub cyfrę albo dziwne znaki lub cokolwiek chcesz.
źródło