Zufällige Zeichenfolgen in Python 2.6 (Ist das in Ordnung?)

77

Ich habe versucht, eine pythonischere Methode zu finden, um zufällige Zeichenfolgen in Python zu generieren, die ebenfalls skaliert werden können. Normalerweise sehe ich etwas Ähnliches

''.join(random.choice(string.letters) for i in xrange(len))

Es ist scheiße, wenn Sie eine lange Zeichenfolge generieren möchten.

Ich habe eine Weile über random.getrandombits nachgedacht und herausgefunden, wie man das in ein Array von Bits konvertiert und dann hexadezimal codiert. Mit Python 2.6 bin ich auf das Bitarray-Objekt gestoßen, das nicht dokumentiert ist. Irgendwie habe ich es zum Laufen gebracht und es scheint sehr schnell zu sein.

In nur 3 Sekunden wird auf meinem Notebook eine zufällige Zeichenfolge von 50 mil generiert.

def rand1(leng):
    nbits = leng * 6 + 1
    bits = random.getrandbits(nbits)
    uc = u"%0x" % bits
    newlen = int(len(uc) / 2) * 2 # we have to make the string an even length
    ba = bytearray.fromhex(uc[:newlen])
    return base64.urlsafe_b64encode(str(ba))[:leng]

bearbeiten

heikogerlach wies darauf hin, dass es eine ungerade Anzahl von Zeichen war, die das Problem verursachten. Neuer Code hinzugefügt, um sicherzustellen, dass immer eine gerade Anzahl von Hex-Ziffern von Hex gesendet wird.

Immer noch neugierig, ob es einen besseren Weg gibt, der genauso schnell ist.

mikelikespie
quelle
1
Wie mache ich das so, dass es nur Zahlen, Buchstaben und Unterstriche enthält? (Dies beinhaltet einen Bindestrich)
Wenbert
2
@wenbert '' .join (random.choice (string.letters + string.digits + "_") für i in xrange (Länge))
yanjost

Antworten:

130
import os
random_string = os.urandom(string_length)

und wenn Sie eine URL-sichere Zeichenfolge benötigen:

import os
random_string = os.urandom(string_length).hex() 

(Beachten Sie, dass die Länge von random_string in diesem Fall größer als string_length ist.)

Seun Osewa
quelle
9
Dies liegt wahrscheinlich daran, dass os.urandom ein kryptografisch sicheres PRNG (normalerweise eine Stream-Verschlüsselung) ist, während random ein "normales" PRNG ist, das normalerweise viel schneller zu berechnen ist.
Joey
6
Gibt es eine Möglichkeit, ASCII-Zeichenfolgen anstelle von Unicode zu generieren? So kann beispielsweise die Zeichenfolge in einer URL verwendet werden.
Derek Dahmer
8
Sie können random.choice, string.digits und string.letters wie im ersten Beispiel verwenden: >>> import random, string >>> '' .join (random.choice (string.letters + string.digits) für i in xrange (10)) 'FywhcRLmh1' (Ich gehe davon aus, dass Sie keine enorme Zeichenfolge wie die Operation generieren, da es sich um eine URL handelt ...)
JJ Geewax
63
Insbesondere habe ich dies verwendet: base64.urlsafe_b64encode (os.urandom (30))
jricher
4
Entschuldigung für das erneute Posten in einem alten Thread. Gibt es eine Möglichkeit, os.urandom(string_length)nur ASCII-Buchstaben zu verwenden und abzurufen? ... Da Python eine interpretierte Sprache ist, scheint die Schleife, die jeweils ein Byte generiert, ziemlich kostspielig zu sein.
BiGYaN
10

Manchmal ist eine UUID kurz genug und wenn Sie die Bindestriche nicht mögen, können Sie sie immer ersetzen ('-', '')

from uuid import uuid4

random_string = str(uuid4())

Wenn Sie eine bestimmte Länge ohne Bindestriche wünschen

random_string_length = 16
str(uuid4()).replace('-', '')[:random_string_length]
Joelbitar
quelle
oder verwenden Sie uuid4().hex, um den Wert ohne Bindestriche zu erhalten
Davoclavo
6

Entnommen aus dem 1023290- Fehlerbericht auf Python.org:

junk_len = 1024
junk =  (("%%0%dX" % junk_len) % random.getrandbits(junk_len *
8)).decode("hex")

Siehe auch die Probleme 923643 und 1023290

fdr
quelle
2

Es scheint, dass die fromhex()Methode eine gerade Anzahl von Hex-Ziffern erwartet. Ihre Zeichenfolge ist 75 Zeichen lang. Beachten Sie, dass something[:-1] umfasst nicht das letzte Element! Einfach benutzen something[:].


quelle
Es gab ein nachfolgendes L mit dem __hex __ (). Ich habe den Beispielcode neu geschrieben. Wie auch immer, ich denke, Sie hatten Recht damit, eine gerade Anzahl von Ziffern zu
benötigen
2

In Bezug auf das letzte Beispiel die folgende Korrektur, um sicherzustellen, dass die Zeile unabhängig vom junk_len-Wert gerade ist:

junk_len = 1024
junk =  (("%%0%dX" % (junk_len * 2)) % random.getrandbits(junk_len * 8)).decode("hex")
user115995
quelle