Leichteste Methode zum Erstellen einer zufälligen Zeichenfolge und einer zufälligen Hexadezimalzahl

90

Was ist die einfachste Methode, um eine zufällige Zeichenfolge mit 30 Zeichen wie die folgende zu erstellen?

ufhy3skj5nca0d2dfh9hwd2tbk9sw1

Und eine hexadezimale Zahl von 30 Stellen wie die folgende?

8c6f78ac23b4a7b8c0182d7a89e9b1

xRobot
quelle
2
Wie (warum?) Wurde keine der (gut ausgearbeiteten) Antworten akzeptiert?
R2evans

Antworten:

119

Ich habe eine schnellere für die Hex-Ausgabe. Verwenden Sie die gleichen t1 und t2 wie oben:

>>> t1 = timeit.Timer("''.join(random.choice('0123456789abcdef') for n in xrange(30))", "import random")
>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t3 = timeit.Timer("'%030x' % random.randrange(16**30)", "import random")
>>> for t in t1, t2, t3:
...     t.timeit()
... 
28.165037870407104
9.0292739868164062
5.2836320400238037

t3 führt nur einen Aufruf des Zufallsmoduls durch, muss keine Liste erstellen oder lesen und erledigt den Rest mit der Formatierung von Zeichenfolgen.

jcdyer
quelle
5
Nett. Generieren Sie einfach eine 30 hexadezimale Zufallszahl und drucken Sie sie aus. Offensichtlich, wenn darauf hingewiesen wird. Schön.
Eemz
Interessanterweise habe ich irgendwie vergessen, dass Python (und das Zufallsmodul) Bigints nativ handhabt.
Wump
3
Siehe yaronfs Antwort unten zur Verwendung von string.hexdigits: stackoverflow.com/a/15462293/311288 " string.hexdigitsgibt 0123456789abcdefABCDEF(sowohl Klein- als auch Großbuchstaben) zurück, [...]. Verwenden Sie stattdessen einfach random.choice('0123456789abcdef')."
Thomas
2
Verwenden Sie getrandbitsstatt randrange, um es noch schneller zu machen.
Robinst
@robinst hat einen guten Punkt. '%030x' % random.getrandbits(60)ist sogar schneller als '%030x' % random.randrange(16**30), wahrscheinlich, weil es keine Konvertierung zu / von Big-Ints machen muss
Dan Lenski
79

30-stellige Hex-Zeichenfolge:

>>> import os,binascii
>>> print binascii.b2a_hex(os.urandom(15))
"c84766ca4a3ce52c3602bbf02ad1f7"

Der Vorteil ist, dass dies die Zufälligkeit direkt vom Betriebssystem erhält, was sicherer und / oder schneller als das random () sein kann und Sie es nicht festlegen müssen.

wump
quelle
Das ist interessant und wahrscheinlich eine gute Wahl, um die gewünschte 30-stellige Hex-Zahl zu generieren. könnte wahrscheinlich urandom und einen Slice-Operator verwenden, um auch die alphanumerische Zeichenfolge zu generieren.
Eemz
Ich habe mir die anderen Funktionen in binascii angesehen, sie haben base64 und uuencode, aber keine Möglichkeit, die erste Art von Strings zu generieren, die er will (base36).
Wump
1
Ist dies zufällig / eindeutig genug, um beispielsweise in Sitzungstoken verwendet zu werden?
Moraes
Wie gibt man die Länge an?
3kstc
50

In Py3.6 + können Sie auch das neue Standardmodul verwenden secrets:

>>> import secrets
>>> secrets.token_hex(15)
'8d9bad5b43259c6ee27d9aadc7b832'
>>> secrets.token_urlsafe(22)   # may include '_-' unclear if that is acceptable
'teRq7IqhaRU0S3euX1ji9f58WzUkrg'
Ein Champion
quelle
28
import string
import random
lst = [random.choice(string.ascii_letters + string.digits) for n in xrange(30)]
str = "".join(lst)
print str
ocwbKCiuAJLRJgM1bWNV1TPSH0F2Lb
eemz
quelle
6
und random.choice (string.hexdigits)
eemz
1
Man könnte das kryptografisch sicherere bevorzugenrandom.SystemRandom().choice
Brian M. Hunt
1
xrange () sollte range () sein - NameError: Name 'xrange' ist nicht definiert
Caleb Bramwell
xrange ist korrekt (und normalerweise besser) in Python 2.x
jcdyer
25

Dramatisch schnellere Lösung als hier:

timeit("'%0x' % getrandbits(30 * 4)", "from random import getrandbits")
0.8056681156158447
Kurt Spindler
quelle
Ein Benutzer muss alle Methoden auf demselben Computer ausprobieren, um eine genaue Basislinie zu erhalten. Hardwarespezifikationen können einen großen Unterschied machen. >>>> timeit.timeit ("'% 0x'% getrandbits (30 * 4)", "vom zufälligen Import getrandbits") 0.2471246949999113 </ pre>
ptay
Vielen Dank, dies viel schneller als die anderen oben. %timeit '%030x' % randrange(16**30)gibt 1000000 Schleifen, am besten 3: 1,61 µs pro Schleife, während %timeit '%0x' % getrandbits(30 * 4)1000000 Schleifen, am besten 3: 396 ns pro Schleife
frmdstryr
15

Hinweis: random.choice(string.hexdigits)ist falsch, da string.hexdigitszurückgegeben wird 0123456789abcdefABCDEF(sowohl in Klein- als auch in Großbuchstaben), sodass Sie ein voreingenommenes Ergebnis erhalten, bei dem die hexadezimale Ziffer 'c' doppelt so häufig erscheint wie die Ziffer '7'. Verwenden Sie stattdessen einfach random.choice('0123456789abcdef').

Yaronf
quelle
6

Eine andere Methode :

from Crypto import Random
import binascii

my_hex_value = binascii.hexlify(Random.get_random_bytes(30))

Der Punkt ist: Der Bytewert ist immer gleich dem Wert in hex .

dsgdfg
quelle
5

einzeilige Funktion:

import random
import string

def generate_random_key(length):
    return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(length))

print generate_random_key(30)
Boubakr
quelle
2

Dies ist übrigens das Ergebnis der Verwendung timeitder beiden vorgeschlagenen Ansätze:

Verwenden von random.choice():

>>> t1 = timeit.Timer("''.join(random.choice(string.hexdigits) for n in xrange(30))", "import random, string")
>>> t1.timeit()
69.558588027954102

Verwenden von binascii.b2a_hex():

>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t2.timeit()
16.288421154022217
David Narayan
quelle
2

Es gibt eine schnellere im Vergleich zu dem, was jcdyer erwähnt hat. Dies dauert ~ 50% seiner schnellsten Methode.

from numpy.random.mtrand import RandomState
import binascii
rand = RandomState()

lo = 1000000000000000
hi = 999999999999999999
binascii.b2a_hex(rand.randint(lo, hi, 2).tostring())[:30]

>>> timeit.Timer("binascii.b2a_hex(rand.randint(lo,hi,2).tostring())[:30]", \
...                 'from __main__ import lo,hi,rand,binascii').timeit()
1.648831844329834         <-- this is on python 2.6.6
2.253110885620117         <-- this on python 2.7.5

Wenn Sie in base64 wollen:

binascii.b2a_base64(rand.randint(lo, hi, 3).tostring())[:30]

Sie können den an randint (last arg) übergebenen Größenparameter ändern, um die Ausgabelänge je nach Ihren Anforderungen zu variieren. Also, für einen 60 Zeichen:

binascii.b2a_hex(rand.randint(lo, hi, 4).tostring())[:60]
Ethan
quelle
Eine kleine Abweichung: binascii.b2a_hex(np.random.rand(np.ceil(N/16)).view(dtype=int))[:N]wo N=30.
Dan-Man
@ dan-man Danke für diese optionale Methode. Ich finde jedoch, dass es mindestens 5x mehr Zeit verbraucht. Merkst du das auch?
Ethan
1
In [1]: import random                                    

In [2]: hex(random.getrandbits(16))                      
Out[2]: '0x3b19'
Bob
quelle
Zu Ihrer Information: Diese Antwort wurde als minderwertig gekennzeichnet. Vielleicht möchten Sie sie verbessern.
Oguz Ismail
Verbesserungsvorschläge?
Bob
Keine Ahnung. Ich dachte nur, du solltest das wissen
oguz ismail
0

Hinzufügen einer weiteren Antwort zu der Mischung, die schneller als die @ ememz-Lösung ist und außerdem vollständig alphanumerisch ist. Beachten Sie, dass dies nicht nicht geben Sie eine hexadezimale Antwort.

import random
import string

LETTERS_AND_DIGITS = string.ascii_letters + string.digits

def random_choice_algo(width):
  return ''.join(random.choice(LETTERS_AND_DIGITS) for i in range(width))

def random_choices_algo(width):
  return ''.join(random.choices(LETTERS_AND_DIGITS, k=width))


print(generate_random_string(10))
# prints "48uTwINW1D"

eine schnelle Benchmark-Rendite

from timeit import timeit
from functools import partial

arg_width = 10
print("random_choice_algo", timeit(partial(random_choice_algo, arg_width)))
# random_choice_algo 8.180561417000717
print("random_choices_algo", timeit(partial(random_choices_algo, arg_width)))
# random_choices_algo 3.172438014007639
andykais
quelle
0

Dies ist sicherlich nicht die leichteste Version, aber es ist zufällig und es ist einfach, das gewünschte Alphabet / die gewünschte Länge anzupassen:

import random

def generate(random_chars=12, alphabet="0123456789abcdef"):
    r = random.SystemRandom()
    return ''.join([r.choice(alphabet) for i in range(random_chars)])
Martin Thoma
quelle